React Router v7 (library mode)

Learn about Sentry's React Router v7 integration.

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

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

If you choose to create your router instance with createBrowserRouter or createMemoryRouter, you can use Sentry.wrapCreateBrowserRouterV7 or Sentry.wrapCreateMemoryRouterV7 to wrap it with the instrumentation:

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

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

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

const sentryCreateBrowserRouter = Sentry.wrapCreateBrowserRouterV7(
  createBrowserRouter,
);

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

If you're using the <Routes /> component to define your routes, wrap Routes using Sentry.withSentryReactRouterV7Routing. This creates a higher order component, which will enable Sentry to reach your router context. You can also use Sentry.withSentryReactRouterV7Routing 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";

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

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

const SentryRoutes = Sentry.withSentryReactRouterV7Routing(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.wrapUseRoutesV7 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";

import { wrapUseRoutes } from "@sentry/react";

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

const useSentryRoutes = wrapUseRoutesV7(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.

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

Copied
// router setup
const sentryCreateBrowserRouter = wrapCreateBrowserRouterV7(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").