--- name: sentry-react-router-framework-sdk description: Full Sentry SDK setup for React Router Framework mode. Use when asked to "add Sentry to React Router Framework", "install @sentry/react-router", or configure error monitoring, tracing, profiling, session replay, logs, or user feedback for a React Router v7 framework app. license: Apache-2.0 category: sdk-setup parent: sentry-sdk-setup disable-model-invocation: true --- > [All Skills](../../SKILL_TREE.md) > [SDK Setup](../sentry-sdk-setup/SKILL.md) > React Router Framework SDK # Sentry React Router Framework SDK Opinionated wizard that scans your React Router Framework project and guides you through complete Sentry setup across client and server entry points. ## Invoke This Skill When - User asks to "add Sentry to React Router Framework" or "set up Sentry in React Router v7 framework mode" - User wants to install or configure `@sentry/react-router` - User uses React Router framework entry files (`entry.client.tsx`, `entry.server.tsx`) and wants tracing/error capture - User asks about `reactRouterTracingIntegration`, `sentryOnError`, `createSentryHandleRequest`, or React Router wizard setup > **Important:** This SDK is currently beta. > For React Router non-framework/data/declarative mode (v5/v6/v7), use `sentry-react-sdk` with `@sentry/react` integrations instead. --- ## Phase 1: Detect Run these commands to understand the project before making any recommendations: ```bash # Detect React Router Framework indicators and versions cat package.json | grep -E '"react-router"|"@react-router/"|"react-router-dev"|"react-router-serve"' # Detect Sentry package choice cat package.json | grep -E '"@sentry/react-router"|"@sentry/react"|"@sentry/profiling-node"' # Check entry point visibility and server instrumentation files ls entry.client.tsx entry.server.tsx instrument.server.mjs react-router.config.ts vite.config.ts 2>/dev/null # Check if React Router files are still hidden (framework mode helper command available) cat package.json | grep -E '"reveal"|react-router' # Detect runtime startup scripts and import strategy cat package.json | grep -E '"dev"|"start"|NODE_OPTIONS|--import' # Detect optional logging/profile-related dependencies cat package.json | grep -E '"pino"|"winston"|"@sentry/profiling-node"' # Detect companion backend directories ls ../backend ../server ../api 2>/dev/null cat ../go.mod ../requirements.txt ../Gemfile ../pom.xml 2>/dev/null | head -3 ``` **What to determine:** | Question | Impact | |----------|--------| | `@sentry/react-router` already installed? | Skip install and move to feature setup | | Framework entry files exposed? | Need `npx react-router reveal` before manual config | | Using `@sentry/react` instead? | This is likely non-framework routing; redirect to `sentry-react-sdk` | | `react-router.config.ts` + Vite config present? | Source map upload and build-end hook setup path | | `NODE_OPTIONS --import` available? | Preferred server instrumentation startup path | | `@sentry/profiling-node` desired/available? | Enable server profiling integration | | Backend directory found? | Trigger Phase 4 cross-link suggestion | --- ## Phase 2: Recommend Present a concrete recommendation based on what you found. Do not ask open-ended questions — lead with a proposal: **Recommended (core coverage):** - ✅ **Error Monitoring** — always; captures client and server errors with framework hooks - ✅ **Tracing** — recommended baseline in framework apps with client/server request flow - ✅ **Session Replay** — recommended for user-facing applications **Optional (enhanced observability):** - ⚡ **Profiling** — server-side profiling with `@sentry/profiling-node` - ⚡ **Logs** — structured `Sentry.logger.*` ingestion and correlation - ⚡ **User Feedback** — in-app feedback widget/reporting flows **Recommendation logic:** | Feature | Recommend when... | |---------|------------------| | Error Monitoring | **Always** — non-negotiable baseline | | Tracing | **Usually yes** in framework apps; route and request timing is high-value | | Session Replay | User-facing product or difficult UX debugging | | Profiling | Server performance investigations needed; Node runtime compatibility verified | | Logs | Team wants log-search and trace correlation in Sentry | | User Feedback | Product/support teams need direct in-app issue reports | Propose: *"I recommend Error Monitoring + Tracing + Session Replay first. Want me to also enable Profiling, Logs, and User Feedback?"* --- ## Phase 3: Guide ### Option 1: Wizard (Recommended) > **You need to run this yourself** — the wizard is interactive and may require browser login: > > ```bash > npx @sentry/wizard@latest -i reactRouter > ``` > > It installs `@sentry/react-router`, exposes React Router entry files, creates instrumentation files, updates root error handling, configures source map upload, and adds verification examples. > > **Once it finishes, continue at [Verification](#verification).** If the user skips wizard setup, continue with manual setup below. --- ### Option 2: Manual Setup #### Install packages ```bash npm install @sentry/react-router --save ``` If profiling is needed: ```bash npm install @sentry/profiling-node --save ``` #### Expose framework entry files ```bash npx react-router reveal ``` #### Configure client in `entry.client.tsx` ```tsx import * as Sentry from "@sentry/react-router"; import { startTransition, StrictMode } from "react"; import { hydrateRoot } from "react-dom/client"; import { HydratedRouter } from "react-router/dom"; Sentry.init({ dsn: "___PUBLIC_DSN___", sendDefaultPii: true, integrations: [ Sentry.reactRouterTracingIntegration(), Sentry.replayIntegration(), Sentry.feedbackIntegration({ colorScheme: "system" }), ], enableLogs: true, tracesSampleRate: 1.0, tracePropagationTargets: [/^\//, /^https:\/\/yourserver\.io\/api/], replaysSessionSampleRate: 0.1, replaysOnErrorSampleRate: 1.0, }); startTransition(() => { hydrateRoot( document, , ); }); ``` #### Configure server in `instrument.server.mjs` ```javascript import * as Sentry from "@sentry/react-router"; import { nodeProfilingIntegration } from "@sentry/profiling-node"; Sentry.init({ dsn: "___PUBLIC_DSN___", sendDefaultPii: true, enableLogs: true, integrations: [nodeProfilingIntegration()], tracesSampleRate: 1.0, profileSessionSampleRate: 1.0, }); ``` #### Wrap server handlers in `entry.server.tsx` ```tsx import * as Sentry from "@sentry/react-router"; import { createReadableStreamFromReadable } from "@react-router/node"; import { renderToPipeableStream } from "react-dom/server"; import { ServerRouter } from "react-router"; const handleRequest = Sentry.createSentryHandleRequest({ ServerRouter, renderToPipeableStream, createReadableStreamFromReadable, }); export default handleRequest; export const handleError = Sentry.createSentryHandleError({ logErrors: false, }); ``` For custom server logic, use `wrapSentryHandleRequest`, `getMetaTagTransformer`, and manual `Sentry.captureException` in your custom `handleError`. #### Load server instrumentation on startup Prefer `NODE_OPTIONS --import`: ```json { "scripts": { "dev": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router dev", "start": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js" } } ``` Fallback for platforms where runtime flags are restricted: ```tsx import "./instrument.server.mjs"; ``` This direct-import method can result in incomplete auto-instrumentation compared to `--import`. #### Configure source maps `vite.config.ts`: ```typescript import { reactRouter } from "@react-router/dev/vite"; import { sentryReactRouter, type SentryReactRouterBuildOptions, } from "@sentry/react-router"; import { defineConfig } from "vite"; const sentryConfig: SentryReactRouterBuildOptions = { org: "___ORG_SLUG___", project: "___PROJECT_SLUG___", authToken: process.env.SENTRY_AUTH_TOKEN, }; export default defineConfig((config) => { return { plugins: [reactRouter(), sentryReactRouter(sentryConfig, config)], }; }); ``` `react-router.config.ts`: ```typescript import type { Config } from "@react-router/dev/config"; import { sentryOnBuildEnd } from "@sentry/react-router"; export default { ssr: true, buildEnd: async ({ viteConfig, reactRouterConfig, buildManifest }) => { await sentryOnBuildEnd({ viteConfig, reactRouterConfig, buildManifest }); }, } satisfies Config; ``` --- ### For Each Agreed Feature Walk through features one at a time. Load the reference file, follow steps exactly, and verify before moving on: | Feature | Reference | Load when... | |---------|-----------|-------------| | Error Monitoring | `${SKILL_ROOT}/references/error-monitoring.md` | Always | | Tracing | `${SKILL_ROOT}/references/tracing.md` | Route/request performance visibility needed | | Profiling | `${SKILL_ROOT}/references/profiling.md` | Server performance analysis needed | | Session Replay | `${SKILL_ROOT}/references/session-replay.md` | User-facing app | | Logs | `${SKILL_ROOT}/references/logging.md` | Structured logs/correlation needed | | User Feedback | `${SKILL_ROOT}/references/user-feedback.md` | In-app feedback flows needed | | Framework Features | `${SKILL_ROOT}/references/react-router-framework-features.md` | Entry files, wrappers, source maps, startup import strategy | For each feature: `Read ${SKILL_ROOT}/references/.md`, follow steps exactly, verify it works. --- ## Configuration Reference ### Key `Sentry.init()` options | Option | Type | Default | Notes | |--------|------|---------|-------| | `dsn` | `string` | — | Required; SDK disabled when empty | | `sendDefaultPii` | `boolean` | `false` | Includes headers/IP-derived user context | | `integrations` | `Integration[]` | SDK defaults | Add tracing/replay/feedback/profiling integrations | | `enableLogs` | `boolean` | `false` | Enables `Sentry.logger.*` ingestion | | `tracesSampleRate` | `number` | — | Usually `1.0` in testing, lower in production | | `tracePropagationTargets` | `(string|RegExp)[]` | SDK defaults | URLs that receive tracing headers | | `replaysSessionSampleRate` | `number` | — | Fraction of all sessions recorded | | `replaysOnErrorSampleRate` | `number` | — | Fraction of error sessions recorded | | `profileSessionSampleRate` | `number` | — | Fraction of transactions profiled (server profiling) | | `tunnel` | `string` | — | Optional ad-blocker bypass endpoint | | `debug` | `boolean` | `false` | Verbose SDK diagnostics | ### Framework-specific APIs | API | Purpose | |-----|---------| | `reactRouterTracingIntegration()` | Client-side tracing integration for framework mode | | `sentryOnError` | Hooks into React Router `HydratedRouter` error reporting | | `createSentryHandleRequest(...)` | Server request wrapper for framework entry server | | `createSentryHandleError(...)` | Server error handler wrapper | | `wrapServerLoader(...)` / `wrapServerAction(...)` | Manual wrapping for server loaders/actions | | `sentryReactRouter(...)` | Vite plugin for source maps/build integration | | `sentryOnBuildEnd(...)` | React Router build-end hook for source map processing | --- ## Verification ### Wizard-generated path If wizard examples were generated, open `/sentry-example-page` and trigger test actions. ### Manual error test ```tsx export async function loader() { throw new Error("My first Sentry error!"); } ``` ### Manual tracing test ```tsx import * as Sentry from "@sentry/react-router"; export async function loader() { return Sentry.startSpan( { op: "test", name: "My First Test Transaction" }, () => { throw new Error("My first Sentry error!"); }, ); } ``` ### Logs test ```javascript Sentry.logger.info("User example action completed"); Sentry.logger.warn("Slow operation detected", { operation: "data_fetch", duration: 3500 }); Sentry.logger.error("Validation failed", { field: "email", reason: "Invalid email" }); ``` Confirm in Sentry: - **Issues**: errors appear - **Traces**: transaction/span data appears - **Profiles**: profiles appear when profiling enabled - **Replays**: replay entries appear when enabled - **Logs**: log events appear when `enableLogs: true` - **User Feedback**: submissions appear when feedback enabled --- ## Phase 4: Cross-Link After completing React Router Framework setup: 1. Check whether the app is actually non-framework routing (v5/v6/v7 data/declarative with `@sentry/react`). 2. If yes, redirect to `sentry-react-sdk` for non-framework routing integrations. Then check companion backend coverage: ```bash ls ../backend ../server ../api ../go ../python 2>/dev/null cat ../go.mod ../requirements.txt ../pyproject.toml ../Gemfile ../pom.xml 2>/dev/null | head -5 ``` | Backend detected | Suggest skill | |------------------|--------------| | Go | `sentry-go-sdk` | | Python | `sentry-python-sdk` | | Ruby | `sentry-ruby-sdk` | | Node backend services | `sentry-node-sdk` | | Java services | Use `@sentry/java` docs | --- ## Troubleshooting | Issue | Solution | |-------|----------| | `entry.client.tsx` / `entry.server.tsx` missing | Run `npx react-router reveal` first | | Client errors missing | Ensure `HydratedRouter` includes `onError={Sentry.sentryOnError}` | | Server errors missing | Use `createSentryHandleRequest` and `createSentryHandleError` wrappers | | Custom server handlers bypass Sentry | Use `wrapSentryHandleRequest` and manual `captureException` in custom `handleError` | | Source maps not uploaded | Verify `sentryReactRouter` plugin config and `sentryOnBuildEnd` hook | | `SENTRY_AUTH_TOKEN` undefined in Vite config | Load env vars in config or use `.env.sentry-build-plugin` | | Incomplete server auto-instrumentation | Prefer `NODE_OPTIONS='--import ./instrument.server.mjs'` startup | | Profiling data missing | Confirm `@sentry/profiling-node` installed and `nodeProfilingIntegration` enabled | | Running unsupported Node auto-instrumentation version | Use instrumentation API/manual wrappers as documented | | Non-framework app configured with `@sentry/react-router` | Switch to `sentry-react-sdk` + `@sentry/react` for v5/v6/v7 non-framework routes |