React Router v6

Learn about Sentry's React Router v6 integration.

Update your Sentry.browserTracingIntegration to Sentry.reactRouterV6BrowserTracingIntegration and provide the required React hooks and router functions:

  • useEffect hook from react
  • useLocation and useNavigationType hooks from react-router-dom or react-router
  • createRoutesFromChildren and matchRoutes functions from react-router-dom or react-router

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

Copied
import React from "react";
import {
  createBrowserRouter,
  createRoutesFromChildren,
  matchRoutes,
  useLocation,
  useNavigationType,
} 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.wrapCreateBrowserRouterV6(
  createBrowserRouter,
);

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

If you're using the <Routes /> component 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:

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

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

Copied
import React from "react";
import {
  createRoutesFromChildren,
  matchRoutes,
  useLocation,
  useNavigationType,
  useRoutes,
} from "react-router-dom";

import { wrapUseRoutes } 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 useSentryRoutes = wrapUseRoutesV6(useRoutes);

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

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.

When using react-router, errors thrown inside route elements will only be re-thrown in development mode while using strict mode. In production, these errors won't be surfaced unless manually captured. If you don't have a custom error boundary in place, react-router will create a default one that "swallows" all errors.

Note, that this only applies to render method and lifecycle errors since React doesn't need error boundaries to handle errors in event handlers.

To send errors to Sentry while using a custom error boundary, use the Sentry.captureException method:

Copied
// router setup
const sentryCreateBrowserRouter = wrapCreateBrowserRouterV6(createBrowserRouter);
const router = sentryCreateBrowserRouter([
  {
    path: "/",
    element: <YourLayout />,
    children: [
      {
        path: "",
        element: <Outlet />,
        errorElement: <YourCustomRootErrorBoundary />,
        children: [
          // other routes ... 
        ],
      },
    ],
  },
]);

// error boundary
import { useRouteError } from "react-router-dom";
import * as Sentry from "@sentry/react";

export function YourCustomRootErrorBoundary() {
  const error = useRouteError() as Error;

  React.useEffect(() => {
    Sentry.captureException(error);
  }, [error]);

  return (
    <div>
      <h1>Ouch!</h1>
    </div>
  );
}

Help improve this content
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").