Skip to content
Open
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
2 changes: 2 additions & 0 deletions docs/platforms/javascript/common/configuration/options.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ Environments are case-sensitive. The environment name can't contain newlines, sp

Sets the URL that will be used to transport captured events. This can be used to work around ad-blockers or to have more granular control over events sent to Sentry. Adding your DSN is still required when using this option so necessary attributes can be set on the generated Sentry data. This option **requires the implementation** of a custom server endpoint. Learn more and find examples in [Dealing with Ad-Blockers](/platforms/javascript/troubleshooting/#dealing-with-ad-blockers).

The endpoint must forward only the request body to Sentry and accept only your own DSNs. Learn more in [Using the `tunnel` Option](/platforms/javascript/troubleshooting/#using-the-tunnel-option).

</SdkOption>

<PlatformSection supported={['javascript.aws-lambda']}>
Expand Down
51 changes: 49 additions & 2 deletions docs/platforms/javascript/common/troubleshooting/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,28 @@ Sentry.init({
});
```

Once configured, all events will be sent to the `/tunnel` endpoint. This solution, however, requires an additional configuration on the server, as the events now need to be parsed and redirected to Sentry. Here's an example for your server component:
Once configured, all events will be sent to the `/tunnel` endpoint. This solution, however, requires an additional configuration on the server, as the events now need to be parsed and redirected to Sentry.

Your tunnel endpoint must:

- Forward only the request body to Sentry, without the request headers.
- Accept only envelopes whose DSN is on a list of allowed DSNs. Otherwise, anyone can use your endpoint to send requests to other servers.
- Send the envelope only to the host of that DSN.

On a JavaScript server with Fetch API `Request` and `Response` objects, `handleTunnelRequest` from `@sentry/core` (SDK version `10.40.0` and later) does this for you. Starting with versions `10.78.0` (v10) and `11.9.0` (v11), it also rejects requests larger than 20 MiB.

```javascript
import { handleTunnelRequest } from "@sentry/core";

export async function POST(request) {
return handleTunnelRequest({
request,
allowedDsns: ["___PUBLIC_DSN___"],
});
}
```

If you implement the endpoint yourself, here's an example for your server component:

```csharp

Expand Down Expand Up @@ -334,7 +355,7 @@ const SENTRY_PROJECT_IDS = ["123456"];

export const postAction = async ({ request }) => {
try {
const envelopeBytes = await req.arrayBuffer();
const envelopeBytes = await request.arrayBuffer();
const envelope = new TextDecoder().decode(envelopeBytes);
const piece = envelope.split("\n")[0];
const header = JSON.parse(piece);
Expand Down Expand Up @@ -420,6 +441,32 @@ If you would like to copy and paste the snippet directly, here it is minified:

</Expandable>

<Expandable permalink title="Credentials on Tunnel Requests">

The browser SDK doesn't set the [`credentials`](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials) option of `fetch`. With the default value `same-origin`, the browser sends credentials (cookies and HTTP authentication) to a tunnel on the same origin as your app. A tunnel that forwards request headers sends these credentials to Sentry.

<PlatformSection supported={["javascript.nextjs"]}>

The Next.js `tunnelRoute` option handles this for you. See <PlatformLink to="/configuration/build/#tunnelRoute">`tunnelRoute`</PlatformLink>.

</PlatformSection>

Forward only the request body, or tell the browser to send no credentials:

```javascript
Sentry.init({
dsn: "___PUBLIC_DSN___",
tunnel: "/tunnel",
transportOptions: {
fetchOptions: { credentials: "omit" },
},
});
```

If a layer in front of your tunnel requires credentials (for example, Vercel Deployment Protection, Cloudflare Access, or HTTP Basic authentication), it rejects requests without credentials. Keep the default in this case, and make sure that your tunnel doesn't forward the request headers.

</Expandable>

</PlatformCategorySection>

<Expandable permalink title="Third party promise libraries">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ Environments are case-sensitive. The environment name can't contain newlines, sp

Sets the URL that will be used to transport captured events. This can be used to work around ad-blockers or to have more granular control over events sent to Sentry. Adding your DSN is still required when using this option so necessary attributes can be set on the generated Sentry data. This option **requires the implementation** of a custom server endpoint. Learn more and find examples in [Dealing with Ad-Blockers](/platforms/javascript/troubleshooting/#dealing-with-ad-blockers).

The endpoint must forward only the request body to Sentry and accept only your own DSNs. Learn more in [Using the `tunnel` Option](/platforms/javascript/troubleshooting/#using-the-tunnel-option).

</SdkOption>

<SdkOption name="maxBreadcrumbs" type='number' defaultValue="100">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ Note: Enabling this option can lead to longer build times.

<SdkOption name="tunnelRoute" type="string | boolean">
<Alert level="info">
This feature requires **Next.js version 11+** and doesn't currently work with self-hosted Sentry instances.
This feature requires **Next.js version 11+**. Rewrite mode doesn't work with self-hosted Sentry instances.
</Alert>

Tunnel Sentry requests through this route on your Next.js server to prevent ad-blockers from blocking Sentry events from being sent.
Expand All @@ -215,15 +215,73 @@ This option can be set to:
- `true` for auto-generated routes, which are unpredictable and change with each deployment.
- A custom static string path like `/error-monitoring`.

<Expandable level="warning" title="If your middleware blocks requests without a session">

Your middleware (`proxy.ts` or `middleware.ts`) also runs for tunnel requests. On v10, the SDK skips your middleware only in rewrite mode with Webpack. Exclude the tunnel route in its `matcher`. This needs a fixed string, because `true` creates a new path for each build:

```typescript {filename:proxy.ts}
export const config = {
matcher: ["/((?!error-monitoring|_next/static|_next/image|favicon.ico).*)"],
};
```

</Expandable>

Learn more about tunneling in the <PlatformLink to="/troubleshooting/#dealing-with-ad-blockers">troubleshooting section</PlatformLink>.

<Expandable level="warning" title="Using Next.js middleware on Turbopack">
If you're using Turbopack, client-side event recording will fail if your
Next.js middleware intercepts the configured tunnel route. To fix this, set
the route to a fixed string (like `/error-monitoring`) and add a negative
matcher like `(?!error-monitoring)` in your middleware to exclude the tunnel
route. If you're not using Turbopack, Sentry will automatically skip the
tunnel route in your middleware.
The tunnel route works in one of two modes:

- **Rewrite mode** (default): A Next.js rewrite proxies each request to Sentry with all its request headers. Works only with Sentry SaaS DSNs.
- **Handler mode**: A route handler in your app forwards only the request body to Sentry. Works with any DSN.

Starting with versions `10.78.0` (v10) and `11.9.0` (v11), the browser sends tunnel requests in rewrite mode [with `credentials: "omit"`](https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials).
If a layer in front of your app requires credentials (for example, Vercel Deployment Protection or HTTP Basic authentication), it rejects these requests. Use handler mode in this case.
You can also set `credentials: "same-origin"`, but rewrite mode then forwards the credentials to Sentry:

```javascript {filename:instrumentation-client.ts}
Sentry.init({
dsn: "___PUBLIC_DSN___",
transportOptions: {
fetchOptions: { credentials: "same-origin" },
},
});
```

**Handler mode**

<AvailableSince version="10.78.0 (v10) and v11.9.0 (v11)" />

Keep `tunnelRoute` and add this file. If your app uses a `src` directory, add it at `src/app/sentry-tunnel/route.ts`:

```typescript {filename:app/sentry-tunnel/route.ts}
export { POST } from "@sentry/nextjs/tunnel";
```

This works with any `tunnelRoute` value, including `true`. When the SDK finds the file, the build prints this line:

```bash
[@sentry/nextjs] The tunnel route sends events through app/sentry-tunnel/route.ts. Only the event payload goes to Sentry.
```

If the line is missing, the SDK uses rewrite mode.

The handler accepts only the DSN of your server-side SDK. It rejects other DSNs with a `403` and requests larger than 20 MiB with a `413`. If your browser SDK uses a different DSN, list the allowed DSNs:

```typescript {filename:app/sentry-tunnel/route.ts}
import { createSentryTunnelRoute } from "@sentry/nextjs/tunnel";

export const { POST } = createSentryTunnelRoute({
allowedDsns: ["___PUBLIC_DSN___"],
});
```

<Expandable title="Limits of handler mode">

- Handler mode works only with the App Router.
- The SDK doesn't find the file in a route group, such as `app/(group)/sentry-tunnel/`.
- With `"moduleResolution": "node"` in `tsconfig.json`, the type check fails with `Cannot find module '@sentry/nextjs/tunnel'`. Set `moduleResolution` to `bundler`, `node16`, or `nodenext`.
- Each event request runs the route handler. On serverless hosts, this is one function invocation for each request.

</Expandable>

</SdkOption>
Expand Down
3 changes: 3 additions & 0 deletions docs/platforms/javascript/guides/nextjs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ export const onRequestError = Sentry.captureRequestError;

Your `next.config.ts` is wrapped with `withSentryConfig` to enable source map uploads, tunneling (to avoid ad-blockers), and other build-time features.

To forward only the request body to Sentry, add a tunnel route handler (SDK version `10.78.0` and later on v10, `11.9.0` and later on v11). Use the handler if Vercel Deployment Protection or another login protects your app.
Learn more about the [`tunnelRoute` option](/platforms/javascript/guides/nextjs/configuration/build/#tunnelRoute).

</SplitSectionText>
<SplitSectionCode>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,9 @@ Prevent ad blockers from blocking Sentry events by routing them through your Nex
This increases server load. Consider the trade-off for your application.
</Alert>

To forward only the request body to Sentry, also add `app/sentry-tunnel/route.ts` (SDK version `10.78.0` and later on v10, `11.9.0` and later on v11).
Use this file if Vercel Deployment Protection or another login protects your app. Learn more <PlatformLink to="/configuration/build/#tunnelRoute">in `tunnelRoute`</PlatformLink>.

<Expandable title="Using Next.js proxy (middleware) with tunneling">

If you're using Next.js proxy/middleware that intercepts requests, exclude the tunnel route. The file is called `proxy.ts` in Next.js 16+ and `middleware.ts` in Next.js 15:
Expand All @@ -348,6 +351,11 @@ export default withSentryConfig(nextConfig, {
});
```

```typescript {filename:app/sentry-tunnel/route.ts}
// Forward only the request body to Sentry
export { POST } from "@sentry/nextjs/tunnel";
```

</SplitSectionCode>
</SplitSection>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,9 @@ Tunneling works identically for both Webpack and Turbopack. Sentry automatically

Enable tunneling to bypass ad-blockers. Use a fixed route so you can exclude it from middleware if needed.

To forward only the request body to Sentry, add a tunnel route handler (SDK version `10.78.0` and later on v10, `11.9.0` and later on v11).
Use the handler if Vercel Deployment Protection or another login protects your app. Learn more about the [`tunnelRoute` option](/platforms/javascript/guides/nextjs/configuration/build/#tunnelRoute).

<Expandable title="Using random tunnel routes">

You can use `tunnelRoute: true` to auto-generate a random route. However, random routes cannot be excluded from middleware matchers since the route changes on each build. This may cause issues if you have middleware that intercepts all requests.
Expand Down
2 changes: 1 addition & 1 deletion docs/platforms/javascript/guides/react/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ const store = createStore(rootReducer, compose(sentryEnhancer));

### Avoid Ad Blockers With Tunneling (Optional)

Some ad blockers prevent Sentry events from being sent. Use the `tunnel` option to route events through your server.
Some ad blockers prevent Sentry events from being sent. Use the `tunnel` option to route events through your server. Your server must forward only the request body to Sentry and accept only your own DSN.

Learn more about [setting up tunneling](/platforms/javascript/guides/react/troubleshooting/#using-the-tunnel-option).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ description: "Learn how to manually define a Sentry tunnel route in your TanStac
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.
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. It forwards only the request body to Sentry.

## Usage

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ sentryTanstackStart({

<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`.
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`. It forwards only the request body to Sentry.

`tunnelRoute` accepts three shapes:

Expand Down
2 changes: 1 addition & 1 deletion platform-includes/getting-started-tunneling/javascript.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

You can prevent ad blockers from blocking Sentry events using tunneling. Use the `tunnel` option in `Sentry.init` to add an API endpoint in your application that forwards Sentry events to Sentry servers.

This will send all events to the `tunnel` endpoint. However, the events need to be parsed and redirected to Sentry, so you'll need to do additional configuration on the server. You can find a detailed explanation on how to do this on our <PlatformLink to="/troubleshooting/#using-the-tunnel-option"> Troubleshooting page</PlatformLink>.
This will send all events to the `tunnel` endpoint. However, the events need to be parsed and redirected to Sentry, so you'll need to do additional configuration on the server. The endpoint must forward only the request body to Sentry and accept only your own DSN. You can find a detailed explanation on how to do this on our <PlatformLink to="/troubleshooting/#using-the-tunnel-option"> Troubleshooting page</PlatformLink>.

</SplitSectionText>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

You can prevent ad blockers from blocking Sentry events using tunneling. Use the `tunnel` option inside your `hooks.client.(js|ts)` file's `Sentry.init` to add an API endpoint in your application that forwards Sentry events to Sentry servers.

This will send all events to the `tunnel` endpoint. However, the events need to be parsed and redirected to Sentry, so you'll need to do additional configuration on the server. You can find a detailed explanation on how to do this on our [Troubleshooting page](/platforms/javascript/guides/sveltekit/troubleshooting/#using-the-tunnel-option).
This will send all events to the `tunnel` endpoint. However, the events need to be parsed and redirected to Sentry, so you'll need to do additional configuration on the server. The endpoint must forward only the request body to Sentry and accept only your own DSN. You can find a detailed explanation on how to do this on our [Troubleshooting page](/platforms/javascript/guides/sveltekit/troubleshooting/#using-the-tunnel-option).

</SplitSectionText>

Expand Down
Loading