React Router Integration

(Available in version 5.21.0 and above)

React Router support is included in the @sentry/react package since version 5.21.0.

We support integrations for React Router 3, 4, 5, and 6.

React Router v6

(Available in version 7 and above)

To use React Router v6 with Sentry:

Initialize Sentry.reactRouterV6Instrumentation as your routing instrumentation and provide the functions it needs to enable performance

tracingThe process of logging the events that took place during a request, often across multiple services.
:

Copied
- `useEffect` hook from `react`
- `useLocation` and `useNavigationType` hooks from `react-router-dom`
- `createRoutesFromChildren` and `matchRoutes` functions from `react-router-dom` or `react-router` packages.

Usage with React Router 6.4 Data API

(Available in version 7.21.0 and above)

If you choose to create your router instance with createBrowserRouter from the react-router-dom package, you can use Sentry.wrapCreateBrowserRouter to wrap it with the instrumentation:

Copied
import { createBrowserRouter } from "react-router-dom";
import * as Sentry from "@sentry/react";

Sentry.init({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  integrations: [
    new Sentry.BrowserTracing({
      routingInstrumentation: Sentry.reactRouterV6Instrumentation(
        React.useEffect,
        useLocation,
        useNavigationType,
        createRoutesFromChildren,
        matchRoutes
      ),
    }),
  ],
  tracesSampleRate: 1.0,
});

const sentryCreateBrowserRouter = Sentry.wrapCreateBrowserRouter(
  createBrowserRouter
);

const router = sentryCreateBrowserRouter([
  // ...
]);

Usage With <Routes /> Component

If you use the <Routes /> component from react-router-dom to define your routes, wrap Routes using Sentry.withSentryReactRouterV6Routing. This creates a higher order component, which will enable Sentry to reach your router context, as in the example below:

Copied
import React from "react";
import ReactDOM from "react-dom";
import {
  Routes,
  BrowserRouter,
  useLocation,
  useNavigationType,
  createRoutesFromChildren,
  matchRoutes,
} from "react-router-dom";
import * as Sentry from "@sentry/react";

Sentry.init({
  integrations: [
    new Sentry.BrowserTracing({
      routingInstrumentation: Sentry.reactRouterV6Instrumentation(
        React.useEffect,
        useLocation,
        useNavigationType,
        createRoutesFromChildren,
        matchRoutes
      ),
    }),
  ],
  tracesSampleRate: 1.0,
});

const SentryRoutes = Sentry.withSentryReactRouterV6Routing(Routes);

ReactDOM.render(
  <BrowserRouter>
    <SentryRoutes>
      <Route path="/" element={<div>Home</div>} />
    </SentryRoutes>
  </BrowserRouter>
);

Usage With useRoutes Hook

(Available in version 7.12.1 and above)

If you specify your route definitions as an object to the useRoutes hook, use Sentry.wrapUseRoutes to create a patched useRoutes hook that instruments your routes with Sentry.

Copied
import {
  createRoutesFromChildren,
  matchRoutes,
  useLocation,
  useNavigationType,
  useRoutes,
} from "react-router-dom";
import { wrapUseRoutes } from "@sentry/react";
import { useEffect } from "react";

Sentry.init({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  integrations: [
    new Sentry.BrowserTracing({
      routingInstrumentation: Sentry.reactRouterV6Instrumentation(
        useEffect,
        useLocation,
        useNavigationType,
        createRoutesFromChildren,
        matchRoutes
      ),
    }),
  ],
  tracesSampleRate: 1.0,
});

const useSentryRoutes = wrapUseRoutes(useRoutes);

function App() {
  return useSentryRoutes([
    // ...
  ]);
}

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById("root")
);

Now, Sentry should generate pageload/navigation transactions with parameterized transaction names (for example, /teams/:teamid/user/:userid), where applicable.

React Router v4/v5

The React router instrumentation uses the React router library to create pageload/navigation transactions and paramaterize transaction names. Make sure you use a Router component combined with createBrowserHistory (or equivalent).

Parameterized Transaction Names

To get parameterized transaction names (for example, /teams/:teamid/user/:userid instead of /teams/123/user/345), you must explicitly set the routes you want paramaterized. That's because there is no static route config that the SDK can use in React Router v4/v5.

We recommend you use the withSentryRouting higher order component to create a SentryRoute component that will update the match path on render.

Copied
import {Route, Router, Switch } from 'react-router-dom';
import { createBrowserHistory } from 'history';

import * as Sentry from '@sentry/react';

// Create Custom Sentry Route component
const SentryRoute = Sentry.withSentryRouting(Route);

const history = createBrowserHistory();

Sentry.init({
  integrations: [
    new Sentry.BrowserTracing({
      routingInstrumentation: Sentry.reactRouterV5Instrumentation(history),
    }),
  ],

  // We recommend adjusting this value in production, or using tracesSampler
  // for finer control
  tracesSampleRate: 1.0,
});

render() {
  return (
    <Router history={history}>
      <Switch>
        <SentryRoute path="/users/:userid" component={() => <div>UserId</div>} />
        <SentryRoute path="/users" component={() => <div>Users</div>} />
        <SentryRoute path="/" component={() => <div>Home</div>} />
      </Switch>
    </Router>
  );
}

If you don't want to wrap individual routes, you can still specify parameterized routes manually by passing an array of route config objects, per react-router-config, to the instrumentation function call. You'll also need to provide the matchPath function exported from the react-router-dom or react-router packages.

Copied
import { Route, Router, Switch, matchPath } from 'react-router-dom';
import { createBrowserHistory } from 'history';

import * as Sentry from '@sentry/react';

const history = createBrowserHistory();

// Array of Route Config Objects
// Make sure the order of the routes is correct. The longest url under the same parent should be placed first and in decreasing order.
const routes = [{ path: '/users/:userid' }, { path: '/users' }, { path: '/' }];

Sentry.init({
  integrations: [
    new Sentry.BrowserTracing({
      routingInstrumentation: Sentry.reactRouterV5Instrumentation(history, routes, matchPath),
    }),
  ],

  // We recommend adjusting this value in production, or using tracesSampler
  // for finer control
  tracesSampleRate: 1.0,
});

// In your App render:
render() {
  return (
    <Router history={history}>
      <Switch>
         <Route path="/users/:userid" component={() => <div>UserId</div>} />
         <Route path="/users" component={() => <div>Users</div>} />
         <Route path="/" component={() => <div>Home</div>} />
      </Switch>
    </Router>
  );
}

React Router v3

To use the router integration, import and set a custom routing instrumentation and pass it the history, your routes and a match function. React Router v3 support is maintained for React Router >= 3.2.0 and < 4.0.0.

Copied
import * as Router from "react-router";

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

// Routes looks like this:
const routes = (
  <Route path="/">
    <Route path="organizations/">
      <Route path=":orgid" component={() => <div>OrgId</div>} />
      <Route path=":orgid/v1/:teamid" component={() => <div>Team</div>} />
    </Route>
  </Route>
);

Sentry.init({
  integrations: [
    new Sentry.BrowserTracing({
      routingInstrumentation: Sentry.reactRouterV3Instrumentation(
        Router.browserHistory,
        // Must be Plain Routes.
        Router.createRoutes(routes),
        Router.match
      ),
    }),
  ],

  // We recommend adjusting this value in production, or using tracesSampler
  // for finer control
  tracesSampleRate: 1.0,
});

Next Steps:

Help improve this content
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) to suggesting an update ("yeah, this would be better").