diff --git a/docs/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.mdx b/docs/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.mdx
index 7e81d4baf69ba..5e7785e678e95 100644
--- a/docs/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.mdx
+++ b/docs/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.mdx
@@ -180,6 +180,12 @@ On Shopify Oxygen, never import anything directly from `@sentry/cloudflare`. Onl
+
+
+`wrapRequestHandler` doesn't isolate requests from each other. Scope data you set during a request, for example with `setTag` or `setUser`, can show up on events from other concurrent or later requests in the same isolate. Use `wrapRequestHandler` only on runtimes that can't enable `nodejs_compat`, such as Shopify Oxygen. On Cloudflare Workers, wrap your handler with `Sentry.withSentry()` instead, as described in the [Cloudflare guide](/platforms/javascript/guides/cloudflare/).
+
+
+
diff --git a/docs/platforms/javascript/guides/cloudflare/frameworks/hydrogen-remix.mdx b/docs/platforms/javascript/guides/cloudflare/frameworks/hydrogen-remix.mdx
index 0ae565165243d..0bc2d4d382e54 100644
--- a/docs/platforms/javascript/guides/cloudflare/frameworks/hydrogen-remix.mdx
+++ b/docs/platforms/javascript/guides/cloudflare/frameworks/hydrogen-remix.mdx
@@ -37,6 +37,12 @@ On Shopify Oxygen, never import anything directly from `@sentry/cloudflare`. Onl
+
+
+`wrapRequestHandler` doesn't isolate requests from each other. Scope data you set during a request, for example with `setTag` or `setUser`, can show up on events from other concurrent or later requests in the same isolate. Use `wrapRequestHandler` only on runtimes that can't enable `nodejs_compat`, such as Shopify Oxygen. For Remix on Cloudflare Workers, follow the [Remix on Cloudflare guide](/platforms/javascript/guides/cloudflare/frameworks/remix/) instead.
+
+
+
```ts {filename:server.ts}
import { wrapRequestHandler } from "@sentry/cloudflare/request";
import { instrumentBuild } from "@sentry/remix/cloudflare";
diff --git a/docs/platforms/javascript/guides/cloudflare/frameworks/remix.mdx b/docs/platforms/javascript/guides/cloudflare/frameworks/remix.mdx
index e67065e7a1fcc..87b9c85bf2122 100644
--- a/docs/platforms/javascript/guides/cloudflare/frameworks/remix.mdx
+++ b/docs/platforms/javascript/guides/cloudflare/frameworks/remix.mdx
@@ -31,21 +31,23 @@ Choose the features you want to configure, and this guide will show you how:
-Run the command for your preferred package manager to add the Sentry SDK to your application:
+Run the command for your preferred package manager to add the Sentry Remix and Cloudflare SDKs to your application.
+
+With npm, add `--legacy-peer-deps`: `@remix-run/cloudflare` requires `@cloudflare/workers-types` version 4, while Wrangler 4 requires version 5.
```bash {tabTitle:npm}
-npm install @sentry/remix --save
+npm install @sentry/remix @sentry/cloudflare --save --legacy-peer-deps
```
```bash {tabTitle:yarn}
-yarn add @sentry/remix
+yarn add @sentry/remix @sentry/cloudflare
```
```bash {tabTitle:pnpm}
-pnpm add @sentry/remix
+pnpm add @sentry/remix @sentry/cloudflare
```
diff --git a/docs/platforms/javascript/guides/cloudflare/index.mdx b/docs/platforms/javascript/guides/cloudflare/index.mdx
index e94a240552b88..7f5ff39843938 100644
--- a/docs/platforms/javascript/guides/cloudflare/index.mdx
+++ b/docs/platforms/javascript/guides/cloudflare/index.mdx
@@ -82,9 +82,9 @@ Not using Vite? See the Wrangler setup
-Add the Sentry plugin to your existing `vite.config.ts`, next to `cloudflare()`. Both behaviors are experimental in this version, so turn them on explicitly.
+Add the Sentry plugin to your existing `vite.config.ts`, next to `cloudflare()`. Both of its behaviors are on by default.
-`autoInstrumentation` wraps your Worker entry, and any Durable Object, Workflow or Agents SDK class in your wrangler config, at build time, so you don't have to call `Sentry.withSentry()` yourself. `useDiagnosticsChannelInjection` instruments bundled dependencies such as database clients, which is the only way to trace them in the Workers runtime, where the SDK can't patch them at runtime.
+`autoInstrumentation` wraps your Worker entry, and any Durable Object, Workflow or Agents SDK class in your wrangler config, at build time, so you don't have to call `Sentry.withSentry()` yourself. `buildTimeInstrumentation` instruments bundled dependencies such as database clients, which is the only way to trace them in the Workers runtime, where the SDK can't patch them at runtime.
To see its options, which packages it instruments, and how to opt out of either behavior, see Vite Plugin.
@@ -99,12 +99,7 @@ To see its options, which packages it instruments, and how to opt out of either
export default defineConfig({
plugins: [
cloudflare(),
-+ sentryCloudflareVitePlugin({
-+ _experimental: {
-+ autoInstrumentation: true,
-+ useDiagnosticsChannelInjection: true,
-+ },
-+ }),
++ sentryCloudflareVitePlugin(),
],
});
```
diff --git a/platform-includes/getting-started-complete/javascript.remix.mdx b/platform-includes/getting-started-complete/javascript.remix.mdx
index 373689d8ec566..d31428ac10375 100644
--- a/platform-includes/getting-started-complete/javascript.remix.mdx
+++ b/platform-includes/getting-started-complete/javascript.remix.mdx
@@ -186,8 +186,8 @@ Sentry.init({
profileSessionSampleRate: 1.0,
// ___PRODUCT_OPTION_END___ profiling
- // Optionally capture action formData attributes with errors.
- // This requires `sendDefaultPii` set to true as well.
+ // Optionally limit which action formData fields are captured.
+ // Without this option, all fields are captured.
captureActionFormDataKeys: {
key_x: true,
key_y: true,
@@ -208,8 +208,6 @@ Then run your Remix server using the `--import` command line option and point it
```bash
NODE_OPTIONS='--import=./instrument.server.mjs' remix-serve build
-# or
-NODE_OPTIONS='--require=./instrument.server.cjs' remix-serve build
```
@@ -227,10 +225,9 @@ If you use the Express server instead of the built-in Remix server, you can impo
-```typescript {filename: server.(mjs|cjs)}
+```typescript {filename: server.mjs}
// import the Sentry instrumentation file before anything else.
import "./instrument.server.mjs";
-// alternatively `require('./instrument.server.cjs')`
// ...
@@ -253,6 +250,59 @@ const app = express();
+Create a Worker entry file, for example `server.ts` in your project's root folder, and set it as `main` in your wrangler config.
+
+In this file, instrument your Remix server build with `instrumentBuild` from `@sentry/remix/cloudflare`, pass it to `createRequestHandler`, and wrap the exported handler with `Sentry.withSentry()` from `@sentry/cloudflare`. `withSentry` isolates each request, so scope data like tags and users stays on the request that set it.
+
+
+
+Don't also wrap `createRequestHandler` with `makeWrappedCreateRequestHandler`. Combined with `withSentry`, it reports every request twice, as two `http.server` transactions in two different traces.
+
+
+
+
+
+
+```typescript {filename:server.ts}
+import { createRequestHandler } from "@remix-run/cloudflare";
+import * as Sentry from "@sentry/cloudflare";
+import { instrumentBuild } from "@sentry/remix/cloudflare";
+// The server build produced by `remix vite:build`
+import * as remixBuild from "./build/server/index.js";
+
+const handleRequest = createRequestHandler(instrumentBuild(remixBuild));
+
+export default Sentry.withSentry(
+ (env) => ({
+ dsn: "___PUBLIC_DSN___",
+ // ___PRODUCT_OPTION_START___ performance
+
+ // Set tracesSampleRate to 1.0 to capture 100%
+ // of transactions for tracing.
+ // We recommend adjusting this value in production
+ // Learn more at
+ // https://docs.sentry.io/platforms/javascript/configuration/options/#traces-sample-rate
+ tracesSampleRate: 1.0,
+ // ___PRODUCT_OPTION_END___ performance
+ }),
+ {
+ async fetch(request, env, ctx) {
+ return handleRequest(request, { env, ctx });
+ },
+ }
+);
+```
+
+
+
+
+
+
+
+
+
+
+
@@ -276,8 +326,8 @@ export const onRequest = [
tracesSampleRate: 1.0,
// ___PRODUCT_OPTION_END___ performance
- // Optionally capture action formData attributes with errors.
- // This requires `sendDefaultPii` set to true as well.
+ // Optionally limit which action formData fields are captured.
+ // Without this option, all fields are captured.
captureActionFormDataKeys: {
key_x: true,
key_y: true,
@@ -291,15 +341,22 @@ export const onRequest = [
+
+
PlatformSection>
### Capture Server-Side Errors
+
+
-To automatically capture server-side errors, instrument the [`handleError`](https://remix.run/docs/en/main/file-conventions/entry.server#handleerror) function in your server entry point (`entry.server.tsx`). You can wrap your custom error handler with `wrapHandleErrorWithSentry` or directly use `sentryHandleError`:
+To automatically capture server-side errors, export a [`handleError`](https://remix.run/docs/en/main/file-conventions/entry.server#handleerror) function from your server entry point (`entry.server.tsx`). Choose one of the two options:
+
+- Wrap your custom error handler with `wrapHandleErrorWithSentry`.
+- Use `sentryHandleError` directly if you don't have a custom error handler.
@@ -310,7 +367,7 @@ Sentry's Remix SDK automatically records your [`action`](https://remix.run/docs/
-```typescript {filename: entry.server.tsx}
+```typescript {tabTitle:Custom Error Handler} {filename: entry.server.tsx}
import * as Sentry from "@sentry/remix";
export const handleError = Sentry.wrapHandleErrorWithSentry(
@@ -318,8 +375,11 @@ export const handleError = Sentry.wrapHandleErrorWithSentry(
// Custom handleError implementation
}
);
+```
+
+```typescript {tabTitle:Default Error Handler} {filename: entry.server.tsx}
+import * as Sentry from "@sentry/remix";
-// Alternative: Use the Sentry utility function if you don't need to wrap a custom function
export const handleError = Sentry.sentryHandleError;
```
@@ -327,6 +387,37 @@ export const handleError = Sentry.sentryHandleError;
+
+
+
+
+
+
+
+
+To automatically capture server-side errors, export `sentryHandleError` as the [`handleError`](https://remix.run/docs/en/main/file-conventions/entry.server#handleerror) function from your server entry point (`entry.server.tsx`). Without this export, Remix handles errors thrown in loaders and actions itself, and Sentry doesn't receive them.
+
+
+
+Import from `@sentry/remix/cloudflare`, not from `@sentry/remix`. In a Cloudflare server build, `sentryHandleError` from `@sentry/remix` is `undefined`, and no errors are captured.
+
+
+
+
+
+
+```typescript {filename: entry.server.tsx}
+import { sentryHandleError } from "@sentry/remix/cloudflare";
+
+export const handleError = sentryHandleError;
+```
+
+
+
+
+
+
+
### Configure Cloudflare for Sentry
@@ -338,13 +429,114 @@ export const handleError = Sentry.sentryHandleError;
PlatformSection>
+### Configure Vite
+
+
+
+
+
+
+
+Add `sentryRemixVitePlugin` from `@sentry/remix/vite` to your `vite.config.ts`. The plugin:
+
+- Parameterizes client-side transaction names with your route patterns, for example `/users/:id`.
+- Instruments supported server-side dependencies, such as database clients, at build time.
+
+
+
+You can skip this step. Client-side transaction names then use the URL instead of the route pattern.
+
+
+
+
+
+
+```typescript {filename:vite.config.ts} {2, 10}
+import { vitePlugin as remix } from "@remix-run/dev";
+import { sentryRemixVitePlugin } from "@sentry/remix/vite";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ plugins: [
+ remix({
+ // ... your Remix plugin options
+ }),
+ sentryRemixVitePlugin(),
+ ],
+});
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+Add two Sentry plugins to your `vite.config.ts`, next to the Remix plugin:
+
+- `sentryRemixVitePlugin` from `@sentry/remix/vite` parameterizes transaction names with your route patterns, for example `/users/:id`.
+- `sentryCloudflareVitePlugin` from `@sentry/cloudflare/vite` instruments supported bundled dependencies at build time, so you get spans for database clients like `mysql`. Without it, database calls produce no spans and no warning.
+
+Set `ssr.target` to `webworker` and bundle the Sentry packages and any database client you want traced with `ssr.noExternal`. Setting `noExternal: true` bundles every dependency, which works too.
+
+
+
+
+```typescript {filename:vite.config.ts} {2-3, 11-12, 14-17}
+import { vitePlugin as remix } from "@remix-run/dev";
+import { sentryCloudflareVitePlugin } from "@sentry/cloudflare/vite";
+import { sentryRemixVitePlugin } from "@sentry/remix/vite";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ plugins: [
+ remix({
+ // ... your Remix plugin options
+ }),
+ sentryRemixVitePlugin(),
+ sentryCloudflareVitePlugin(),
+ ],
+ ssr: {
+ target: "webworker",
+ noExternal: ["mysql", /^@sentry\//, "@opentelemetry/api"],
+ },
+});
+```
+
+
+
+
+
+
+
+Build your app with `remix vite:build`. Under Vite 6, a plain `vite build` only builds the client and skips `build/server`, without an error.
+
+
+
+
+```bash
+npx remix vite:build
+```
+
+
+
+
+
+
+
### Add Readable Stack Traces With Source Maps (Optional)
-To upload source maps for clear error stack traces, add your Sentry auth token, organization, and project slug in your `vite.config.ts` file:
+To upload source maps for clear error stack traces, install the Sentry Vite plugin:
@@ -356,9 +548,33 @@ alternative setup options.
-```javascript {filename:vite.config.ts} {3, 10-17,20-23}
+```bash {tabTitle:npm}
+npm install @sentry/vite-plugin --save-dev
+```
+
+```bash {tabTitle:yarn}
+yarn add @sentry/vite-plugin --dev
+```
+
+```bash {tabTitle:pnpm}
+pnpm add @sentry/vite-plugin --save-dev
+```
+
+
+
+
+
+
+
+Then add `sentryVitePlugin` with your Sentry auth token, organization, and project slug to your `vite.config.ts` file, and enable source map generation. Keep the plugins from the previous step:
+
+
+
+
+```javascript {filename:vite.config.ts} {4, 13-20, 23-26}
import { defineConfig } from "vite";
import { vitePlugin as remix } from "@remix-run/dev";
+import { sentryRemixVitePlugin } from "@sentry/remix/vite";
import { sentryVitePlugin } from "@sentry/vite-plugin";
export default defineConfig({
@@ -366,6 +582,8 @@ export default defineConfig({
remix({
// ... your Remix plugin options
}),
+ sentryRemixVitePlugin(),
+ // ... other plugins
sentryVitePlugin({
// If you use .sentryclirc or environment variables,
// you don't need to specify these options