---
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 |