Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
title: createSentryTunnelRoute
description: "Learn how to manually define a Sentry tunnel route in your TanStack Start app."
---

<AvailableSince version="10.51.0" />

<Alert level="info">
If you can use the `sentryTanstackStart` Vite plugin, prefer its
[`tunnelRoute`](/platforms/javascript/guides/tanstackstart-react/features/sentryTanstackStart/#tunnel-route)
option. It registers the route for you and automatically wires up the client
`tunnel` option. Use `createSentryTunnelRoute` only when you need full control over
the route file, the DSN allowlist, or can't use the Vite plugin.
</Alert>

The `createSentryTunnelRoute` helper returns a TanStack Start server-route configuration with a `POST` handler that forwards Sentry envelopes to Sentry's ingest servers. Use it inside a file route to expose a same-origin tunnel endpoint.

## Usage

Create a server route at the path you want to tunnel through, and pass the list of DSNs you want to allow:

```typescript {filename:src/routes/monitor.ts}
import { createFileRoute } from "@tanstack/react-router";
import * as Sentry from "@sentry/tanstackstart-react";

export const Route = createFileRoute("/monitor")({
server: Sentry.createSentryTunnelRoute({
allowedDsns: ["___PUBLIC_DSN___"],
}),
});
```

Then, set the matching `tunnel` option in your client `Sentry.init()` so the browser SDK sends events to your route instead of directly to Sentry:

```tsx {filename:src/router.tsx} {4}
Sentry.init({
dsn: "___PUBLIC_DSN___",
// ...
tunnel: "/monitor",
});
```

## Options

### `allowedDsns`

A list of DSN strings that the route is allowed to forward to. The route validates each incoming envelope against this list and rejects any DSN that isn't allowed.

If `allowedDsns` is omitted or empty, the route falls back to the DSN of the active server-side Sentry SDK at runtime. If neither is available, requests to the route return a 500 response.

```typescript {filename:src/routes/monitor.ts}
Sentry.createSentryTunnelRoute({
allowedDsns: [
"https://public@o0.ingest.sentry.io/1",
"https://public@o0.ingest.sentry.io/2",
],
});
```
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,61 @@ sentryTanstackStart({
autoInstrumentMiddleware: false,
}),
```

## Tunnel Route

<AvailableSince version="10.51.0" />

The `tunnelRoute` option registers a same-origin TanStack Start server route that forwards Sentry envelopes to Sentry's ingest servers. It also automatically sets the client `tunnel` option in `Sentry.init()` so browser events go through that route. This helps avoid ad blockers and corporate firewalls that block requests to `*.sentry.io`.

`tunnelRoute` accepts three shapes:

### `tunnelRoute: true` (recommended)

Generates an opaque, unguessable route path for each dev session and production build. Because the path changes between builds, ad blockers can't reliably target it.

```typescript {filename:vite.config.ts}
sentryTanstackStart({
tunnelRoute: true,
}),
```

### Static path

Pass a string to use a fixed route path. This is easier to reason about, but a known path is easier for ad blockers to add to a list.

```typescript {filename:vite.config.ts}
sentryTanstackStart({
tunnelRoute: "/monitor",
}),
```

### Object form

Use the object form to control the DSN allowlist or set a static path explicitly:

```typescript {filename:vite.config.ts}
sentryTanstackStart({
tunnelRoute: {
allowedDsns: ["___PUBLIC_DSN___"],
path: "/monitor",
},
}),
```

- **`allowedDsns`** — only envelopes targeting one of these DSNs are forwarded. If omitted or empty, the route falls back to the DSN of the active server-side Sentry SDK at runtime.
- **`path`** — the public route path. If omitted, an opaque path is generated (same behavior as `tunnelRoute: true`).

<Alert
level="info"
title="Setting `tunnel` in `Sentry.init()` overrides this option"
>
If you also pass `tunnel` to `Sentry.init()`, the runtime option wins and the
managed tunnel route is bypassed. The SDK logs a warning when this happens.
</Alert>

<Alert level="warning" title="Opaque paths are not stable">

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a huge fan of back to back Alerts being rendered, is there a better place for this? Not a blocker tho

When using `tunnelRoute: true` (or the object form without `path`), the
generated path changes for each dev session and each production build. Don't
hard-code it elsewhere in your app or infrastructure.
</Alert>
23 changes: 22 additions & 1 deletion docs/platforms/javascript/guides/tanstackstart-react/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,28 @@ If you need more control over the upload process, see our [source maps guide](/p

## Step 5: Avoid Ad Blockers With Tunneling (Optional)

<PlatformContent includePath="getting-started-tunneling" />
Ad blockers and corporate firewalls often block requests to `*.sentry.io`, which can cause events to be dropped before they reach Sentry. To work around this, you can tunnel events through a same-origin route in your TanStack Start app.

The `sentryTanstackStart` Vite plugin can register a tunnel route for you and automatically wire up the client `tunnel` option:

```typescript {filename:vite.config.ts} {9}
import { defineConfig } from "vite";
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import { sentryTanstackStart } from "@sentry/tanstackstart-react/vite";

export default defineConfig({
plugins: [
tanstackStart(),
sentryTanstackStart({
tunnelRoute: true,
}),
],
});
```

With `tunnelRoute: true`, an opaque route path is generated for each dev session and production build, making it harder for ad blockers to target. See the [`sentryTanstackStart`](/platforms/javascript/guides/tanstackstart-react/features/sentryTanstackStart/#tunnel-route) feature page for static paths and the full set of options.

If you can't use the Vite plugin, or you need full control over the route file and DSN allowlist, use [`createSentryTunnelRoute`](/platforms/javascript/guides/tanstackstart-react/features/createSentryTunnelRoute/) to define the route yourself.

## Step 6: Verify

Expand Down
Loading