---
name: sentry-react-sdk
description: Full Sentry SDK setup for React. Use when asked to "add Sentry to React", "install @sentry/react", or configure error monitoring, tracing, session replay, profiling, or logging for React applications. Supports React 16+, React Router v5-v7 non-framework mode, TanStack Router, Redux, Vite, and webpack.
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 SDK

# Sentry React SDK

Opinionated wizard that scans your React project and guides you through complete Sentry setup.

## Invoke This Skill When

- User asks to "add Sentry to React" or "set up Sentry" in a React app
- User wants error monitoring, tracing, session replay, profiling, or logging in React
- User mentions `@sentry/react`, React Sentry SDK, or Sentry error boundaries
- User wants to monitor React Router v5/v6/v7 non-framework navigation, Redux state, or component performance

If project is React Router **Framework mode** using `@sentry/react-router`, use `sentry-react-router-framework-sdk` instead of this skill.

> **Note:** SDK versions and APIs below reflect current Sentry docs at time of writing (`@sentry/react` ≥8.0.0).
> Always verify against [docs.sentry.io/platforms/javascript/guides/react/](https://docs.sentry.io/platforms/javascript/guides/react/) before implementing.

---

## Phase 1: Detect

Run these commands to understand the project before making any recommendations:

```bash
# Detect React version
cat package.json | grep -E '"react"|"react-dom"'

# Check for existing Sentry
cat package.json | grep '"@sentry/'

# Detect router and framework mode hints
cat package.json | grep -E '"react-router-dom"|"react-router"|"@react-router/"|"@tanstack/react-router"|"@sentry/react-router"'

# Detect state management
cat package.json | grep -E '"redux"|"@reduxjs/toolkit"'

# Detect build tool
ls vite.config.ts vite.config.js webpack.config.js craco.config.js 2>/dev/null
cat package.json | grep -E '"vite"|"react-scripts"|"webpack"'

# Detect logging libraries
cat package.json | grep -E '"pino"|"winston"|"loglevel"'

# Check for companion backend in adjacent 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 |
|----------|--------|
| React 19+? | Use `reactErrorHandler()` hook pattern |
| React <19? | Use `Sentry.ErrorBoundary` |
| `@sentry/react` already present? | Skip install, go straight to feature config |
| React Router Framework mode indicators (`@sentry/react-router`, `@react-router/*`)? | Use `sentry-react-router-framework-sdk` |
| `react-router-dom` v5 / v6 / v7? | Determines which router integration to use |
| `@tanstack/react-router`? | Use `tanstackRouterBrowserTracingIntegration()` |
| Redux in use? | Recommend `createReduxEnhancer()` |
| Vite detected? | Source maps via `sentryVitePlugin` |
| CRA (`react-scripts`)? | Source maps via `@sentry/webpack-plugin` in CRACO |
| Backend directory found? | Trigger Phase 4 cross-link suggestion |

---

## Phase 2: Recommend

Present a concrete recommendation based on what you found. Don't ask open-ended questions — lead with a proposal:

**Recommended (core coverage):**
- ✅ **Error Monitoring** — always; captures unhandled errors, React error boundaries, React 19 hooks
- ✅ **Tracing** — React SPAs benefit from page load, navigation, and API call tracing
- ✅ **Session Replay** — recommended for user-facing apps; records sessions around errors

**Optional (enhanced observability):**
- ⚡ **Logging** — structured logs via `Sentry.logger.*`; recommend when structured log search is needed
- ⚡ **Profiling** — JS Self-Profiling API (⚠️ experimental; requires cross-origin isolation headers)

**Recommendation logic:**

| Feature | Recommend when... |
|---------|------------------|
| Error Monitoring | **Always** — non-negotiable baseline |
| Tracing | **Always for React SPAs** — page load + navigation spans are high-value |
| Session Replay | User-facing app, login flows, or checkout pages |
| Logging | App needs structured log search or log-to-trace correlation |
| Profiling | Performance-critical app; server sends `Document-Policy: js-profiling` header |

**React-specific extras:**
- React 19 detected → set up `reactErrorHandler()` on `createRoot`
- React Router v5/v6/v7 non-framework detected → configure matching router integration (see Phase 3)
- React Router Framework mode detected → switch to `sentry-react-router-framework-sdk`
- Redux detected → add `createReduxEnhancer()` to Redux store
- Vite detected → configure `sentryVitePlugin` for source maps (essential for readable stack traces)

Propose: *"I recommend setting up Error Monitoring + Tracing + Session Replay. Want me to also add Logging or Profiling?"*

---

## Phase 3: Guide

### Install

```bash
npm install @sentry/react --save
```

### Create `src/instrument.ts`

Sentry must initialize **before any other code runs**. Put `Sentry.init()` in a dedicated sidecar file:

```typescript
import * as Sentry from "@sentry/react";

Sentry.init({
  dsn: import.meta.env.VITE_SENTRY_DSN, // Adjust per build tool (see table below)
  environment: import.meta.env.MODE,
  release: import.meta.env.VITE_APP_VERSION, // inject at build time

  sendDefaultPii: true,

  integrations: [
    Sentry.browserTracingIntegration(),
    Sentry.replayIntegration({
      maskAllText: true,
      blockAllMedia: true,
    }),
  ],

  // Tracing
  tracesSampleRate: 1.0, // lower to 0.1–0.2 in production
  tracePropagationTargets: ["localhost", /^https:\/\/yourapi\.io/],

  // Session Replay
  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,

  enableLogs: true,
});
```

**DSN environment variable by build tool:**

| Build Tool | Variable Name | Access in code |
|------------|--------------|----------------|
| Vite | `VITE_SENTRY_DSN` | `import.meta.env.VITE_SENTRY_DSN` |
| Create React App | `REACT_APP_SENTRY_DSN` | `process.env.REACT_APP_SENTRY_DSN` |
| Custom webpack | `SENTRY_DSN` | `process.env.SENTRY_DSN` |

### Entry Point Setup

Import `instrument.ts` as the **very first import** in your entry file:

```tsx
// src/main.tsx (Vite) or src/index.tsx (CRA/webpack)
import "./instrument";              // ← MUST be first

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <App />
  </StrictMode>
);
```

### React Version-Specific Error Handling

**React 19+** — use `reactErrorHandler()` on `createRoot`:

```tsx
import { reactErrorHandler } from "@sentry/react";

createRoot(document.getElementById("root")!, {
  onUncaughtError: reactErrorHandler(),
  onCaughtError: reactErrorHandler(),
  onRecoverableError: reactErrorHandler(),
}).render(<App />);
```

**React <19** — wrap your app in `Sentry.ErrorBoundary`:

```tsx
import * as Sentry from "@sentry/react";

createRoot(document.getElementById("root")!).render(
  <Sentry.ErrorBoundary fallback={<p>Something went wrong</p>} showDialog>
    <App />
  </Sentry.ErrorBoundary>
);
```

Use `<Sentry.ErrorBoundary>` for any sub-tree that should catch errors independently (route sections, widgets, etc.).

### Router Integration

Configure the matching integration for your router (non-framework mode):

| Router | Integration | Notes |
|--------|------------|-------|
| React Router v7 | `reactRouterV7BrowserTracingIntegration` | `useEffect`, `useLocation`, `useNavigationType`, `createRoutesFromChildren`, `matchRoutes` from `react-router` |
| React Router v6 | `reactRouterV6BrowserTracingIntegration` | `useEffect`, `useLocation`, `useNavigationType`, `createRoutesFromChildren`, `matchRoutes` from `react-router-dom` |
| React Router v5 | `reactRouterV5BrowserTracingIntegration` | Wrap routes in `withSentryRouting(Route)` |
| TanStack Router | `tanstackRouterBrowserTracingIntegration(router)` | Pass router instance — no hooks required |
| No router / custom | `browserTracingIntegration()` | Names transactions by URL path |

**React Router v6/v7 setup:**

```typescript
// in instrument.ts integrations array:
import React from "react";
import {
  createRoutesFromChildren, matchRoutes,
  useLocation, useNavigationType,
} from "react-router-dom"; // or "react-router" for v7
import * as Sentry from "@sentry/react";
import { reactRouterV6BrowserTracingIntegration } from "@sentry/react";
import { createBrowserRouter } from "react-router-dom";

// Option A — createBrowserRouter (recommended for v6.4+):
const sentryCreateBrowserRouter = Sentry.wrapCreateBrowserRouterV6(createBrowserRouter);
const router = sentryCreateBrowserRouter([...routes]);

// Option B — createBrowserRouter for React Router v7:
// const sentryCreateBrowserRouter = Sentry.wrapCreateBrowserRouterV7(createBrowserRouter);

// Option C — integration with hooks (v6 without data APIs):
Sentry.init({
  integrations: [
    reactRouterV6BrowserTracingIntegration({
      useEffect: React.useEffect,
      useLocation,
      useNavigationType,
      matchRoutes,
      createRoutesFromChildren,
    }),
  ],
});
```

**TanStack Router setup:**

```typescript
import { tanstackRouterBrowserTracingIntegration } from "@sentry/react";

// Pass your TanStack router instance:
Sentry.init({
  integrations: [tanstackRouterBrowserTracingIntegration(router)],
});
```

### Redux Integration (when detected)

```typescript
import * as Sentry from "@sentry/react";
import { configureStore } from "@reduxjs/toolkit";

const store = configureStore({
  reducer: rootReducer,
  enhancers: (getDefaultEnhancers) =>
    getDefaultEnhancers().concat(Sentry.createReduxEnhancer()),
});
```

### Source Maps Setup (strongly recommended)

Without source maps, stack traces show minified code. Set up the build plugin to upload source maps automatically:

**Vite (`vite.config.ts`):**

```typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { sentryVitePlugin } from "@sentry/vite-plugin";

export default defineConfig({
  build: { sourcemap: "hidden" },
  plugins: [
    react(),
    sentryVitePlugin({
      org: process.env.SENTRY_ORG,
      project: process.env.SENTRY_PROJECT,
      authToken: process.env.SENTRY_AUTH_TOKEN,
    }),
  ],
});
```

Add to `.env` (never commit):
```bash
SENTRY_AUTH_TOKEN=sntrys_...
SENTRY_ORG=my-org-slug
SENTRY_PROJECT=my-project-slug
```

**Create React App (via CRACO):**

```bash
npm install @craco/craco @sentry/webpack-plugin --save-dev
```

```javascript
// craco.config.js
const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");

module.exports = {
  webpack: {
    plugins: {
      add: [
        sentryWebpackPlugin({
          org: process.env.SENTRY_ORG,
          project: process.env.SENTRY_PROJECT,
          authToken: process.env.SENTRY_AUTH_TOKEN,
        }),
      ],
    },
  },
};
```

### For Each Agreed Feature

Walk through features one at a time. Load the reference file, follow its steps, verify before moving on:

| Feature | Reference | Load when... |
|---------|-----------|-------------|
| Error Monitoring | `${SKILL_ROOT}/references/error-monitoring.md` | Always (baseline) |
| Tracing | `${SKILL_ROOT}/references/tracing.md` | SPA navigation / API call tracing |
| Session Replay | `${SKILL_ROOT}/references/session-replay.md` | User-facing app |
| Logging | `${SKILL_ROOT}/references/logging.md` | Structured log search / log-to-trace |
| Profiling | `${SKILL_ROOT}/references/profiling.md` | Performance-critical app |
| React Features | `${SKILL_ROOT}/references/react-features.md` | Redux, component tracking, source maps, integrations catalog |

For each feature: `Read ${SKILL_ROOT}/references/<feature>.md`, follow steps exactly, verify it works.

---

## Configuration Reference

### Key `Sentry.init()` Options

| Option | Type | Default | Notes |
|--------|------|---------|-------|
| `dsn` | `string` | — | **Required.** SDK disabled when empty |
| `environment` | `string` | `"production"` | e.g., `"staging"`, `"development"` |
| `release` | `string` | — | e.g., `"my-app@1.0.0"` or git SHA — links errors to releases |
| `sendDefaultPii` | `boolean` | `false` | Includes IP addresses and request headers |
| `tracesSampleRate` | `number` | — | 0–1; `1.0` in dev, `0.1–0.2` in prod |
| `tracesSampler` | `function` | — | Per-transaction sampling; overrides rate |
| `tracePropagationTargets` | `(string\|RegExp)[]` | — | Outgoing URLs that receive distributed tracing headers |
| `replaysSessionSampleRate` | `number` | — | Fraction of all sessions recorded |
| `replaysOnErrorSampleRate` | `number` | — | Fraction of error sessions recorded |
| `enableLogs` | `boolean` | `false` | Enable `Sentry.logger.*` API |
| `attachStacktrace` | `boolean` | `false` | Stack traces on `captureMessage()` calls |
| `maxBreadcrumbs` | `number` | `100` | Breadcrumbs stored per event |
| `debug` | `boolean` | `false` | Verbose SDK output to console |
| `tunnel` | `string` | — | Proxy URL to bypass ad blockers |

### React Compatibility Matrix

| React Version | Error handling approach | SDK minimum |
|---------------|------------------------|-------------|
| React 19+ | `reactErrorHandler()` on `createRoot` | `@sentry/react` ≥8.0.0 |
| React 16–18 | `Sentry.ErrorBoundary` component | `@sentry/react` ≥7.0.0 |
| React 16 | `componentDidCatch` class boundaries | `@sentry/react` ≥6.0.0 |

---

## Verification

Trigger test events to confirm Sentry is receiving data:

```tsx
// Add a temporary test button anywhere in your app
import * as Sentry from "@sentry/react";

function SentryTest() {
  return (
    <>
      <button onClick={() => { throw new Error("Sentry React test error"); }}>
        Test Error
      </button>
      <button onClick={() => Sentry.captureMessage("Sentry test message", "info")}>
        Test Message
      </button>
    </>
  );
}
```

Check the Sentry dashboard:
- **Issues** → error appears within seconds
- **Traces** → page load and navigation transactions visible
- **Replays** → session recording visible after page interaction
- **Logs** → structured log entries if logging enabled

Set `debug: true` in `Sentry.init()` and check the browser console if nothing appears.

---

## Phase 4: Cross-Link

After completing React setup, check for a companion backend missing Sentry coverage:

```bash
ls ../backend ../server ../api ../go ../python 2>/dev/null
cat ../go.mod 2>/dev/null | head -3
cat ../requirements.txt ../pyproject.toml 2>/dev/null | head -3
cat ../Gemfile 2>/dev/null | head -3
cat ../pom.xml 2>/dev/null | grep '<artifactId>' | head -3
```

If a backend exists without Sentry configured, suggest the matching skill:

| Backend detected | Suggest skill |
|-----------------|--------------|
| Go (`go.mod`) | `sentry-go-sdk` |
| Python (`requirements.txt`, `pyproject.toml`) | `sentry-python-sdk` |
| Ruby (`Gemfile`) | `sentry-ruby-sdk` |
| Java (`pom.xml`, `build.gradle`) | Use `@sentry/java` — see [docs.sentry.io/platforms/java/](https://docs.sentry.io/platforms/java/) |
| Node.js (Express, Fastify) | Use `@sentry/node` — see [docs.sentry.io/platforms/javascript/guides/express/](https://docs.sentry.io/platforms/javascript/guides/express/) |

---

## Troubleshooting

| Issue | Solution |
|-------|----------|
| Events not appearing | Set `debug: true`, check DSN, open browser console for SDK errors |
| Source maps not working | Build in production mode (`npm run build`); verify `SENTRY_AUTH_TOKEN` is set |
| Minified stack traces | Source maps not uploading — check plugin config and auth token |
| `instrument.ts` not running first | Verify it's the first import in entry file before React/app imports |
| React 19 errors not captured | Confirm `reactErrorHandler()` is passed to all three `createRoot` options |
| React <19 errors not captured | Ensure `<Sentry.ErrorBoundary>` wraps the component tree |
| Router transactions named `<unknown>` | Add router integration matching your router version |
| `tracePropagationTargets` not matching | Check regex escaping; default is `localhost` and your DSN origin only |
| Session replay not recording | Confirm `replayIntegration()` is in init; check `replaysSessionSampleRate` |
| Redux actions not in breadcrumbs | Add `Sentry.createReduxEnhancer()` to store enhancers |
| Ad blockers dropping events | Set `tunnel: "/sentry-tunnel"` and add server-side relay endpoint |
| High replay storage costs | Lower `replaysSessionSampleRate`; keep `replaysOnErrorSampleRate: 1.0` |
| Profiling not working | Verify `Document-Policy: js-profiling` header is set on document responses |
