React Router
Learn about Sentry's 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
.
Note
The React Router integration is designed to work with Sentry Tracing. Please see Set Up Tracing with React for more details on how to set up and install the SDK.
The React Router instrumentation uses the React Router library to create pageload/navigation
transactions to ensure you collect meaningful performance data about the health of your page loads and associated requests.
We support integrations for React Router 3, 4, 5, and 6.
(Available in version 7 and above)
To use React Router v6 with Sentry:
Add Sentry.reactRouterV6BrowserTracingIntegration
instead of the regular Sentry.browserTracingIntegration
and provide the functions it needs to enable performance tracing:
useEffect
hook fromreact
useLocation
anduseNavigationType
hooks fromreact-router-dom
createRoutesFromChildren
andmatchRoutes
functions fromreact-router-dom
orreact-router
packages.
Make sure Sentry.reactRouterV6BrowserTracingIntegration
is initialized by your Sentry.init
call, before you wrap <Routes />
component or useRoutes
hook. Otherwise, the routing instrumentation may not work properly.
(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:
import { createBrowserRouter } from "react-router-dom";
import * as Sentry from "@sentry/react";
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
Sentry.reactRouterV6BrowserTracingIntegration({
useEffect: React.useEffect,
useLocation,
useNavigationType,
createRoutesFromChildren,
matchRoutes,
}),
],
tracesSampleRate: 1.0,
});
const sentryCreateBrowserRouter = Sentry.wrapCreateBrowserRouter(
createBrowserRouter,
);
const router = sentryCreateBrowserRouter([
// ...
]);
Note
You can instrument createMemoryRouter
and createHashRouter
using the wrapCreateBrowserRouter
function.
If you're using 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. You can also use Sentry.withSentryReactRouterV6Routing
for Routes
inside BrowserRouter
. MemoryRouter
, and HashRouter
components:
import React from "react";
import ReactDOM from "react-dom";
import {
Routes,
Route,
BrowserRouter,
useLocation,
useNavigationType,
createRoutesFromChildren,
matchRoutes,
} from "react-router-dom";
import * as Sentry from "@sentry/react";
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
Sentry.reactRouterV6BrowserTracingIntegration({
useEffect: 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>,
);
This is only needed at the top level of your app, rather than how v4/v5 required wrapping every <Route/>
you wanted parametrized.
(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.
wrapUseRoutes
should be called outside of a React component, as in the example below. It's also recommended that you assign the wrapped hook to a variable name starting with use
, as per the React documentation.
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: [
Sentry.reactRouterV6BrowserTracingIntegration({
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. This is only needed at the top level of your app, rather than how v4/v5 required wrapping every <Route/>
you wanted parametrized.
Make sure you use a Router
component combined with createBrowserHistory
(or equivalent).
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 parameterized. 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.
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({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
Sentry.reactRouterV5BrowserTracingIntegration({ history }),
// or
Sentry.reactRouterV4BrowserTracingIntegration({ 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.
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({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
Sentry.reactRouterV5BrowserTracingIntegration({
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>
);
}
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.
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({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
Sentry.reactRouterV3BrowserTracingIntegration({
history: Router.browserHistory,
// Must be Plain Routes.
routes: Router.createRoutes(routes),
match: Router.match,
}),
],
// We recommend adjusting this value in production, or using tracesSampler
// for finer control
tracesSampleRate: 1.0,
});
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").