---
title: "React Router v7 (non-framework)"
description: "Learn how to instrument your React Router v7 application with Sentry."
url: https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/v7/
---

# React Router v7 (non-framework) | Sentry for React

##### Looking for framework mode?

React Router v7 (framework mode) is currently in Beta, check out the docs [here](https://docs.sentry.io/platforms/javascript/guides/react-router.md).

Apply the following setup steps based on your routing method and create a [custom error boundary](https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/v7.md#set-up-a-custom-error-boundary) to make sure Sentry automatically captures rendering errors:



## [Usage with `createBrowserRouter` or `createMemoryRouter` (Data Mode)](https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/v7.md#usage-with-createbrowserrouter-or-creatememoryrouter-data-mode)

To instrument your React Router, update your `Sentry.browserTracingIntegration` to `Sentry.reactRouterV7BrowserTracingIntegration` within `Sentry.init` and provide the required React hooks and router functions. Then, wrap the router instance created by `createBrowserRouter` or `createMemoryRouter` with one of the following functions:

* Use `Sentry.wrapCreateBrowserRouterV7` for [`createBrowserRouter`](https://reactrouter.com/en/main/routers/create-browser-router) and [`createHashRouter`](https://reactrouter.com/en/main/routers/create-hash-router)
* Use `Sentry.wrapCreateMemoryRouterV7` for [`createMemoryRouter`](https://reactrouter.com/en/main/routers/create-memory-router) (introduced in SDK version `8.50.0`)

```javascript
import React from "react";

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


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

Sentry.init({
  dsn: "___PUBLIC_DSN___",
  integrations: [

    Sentry.reactRouterV7BrowserTracingIntegration({
      useEffect: React.useEffect,
      useLocation,
      useNavigationType,
      createRoutesFromChildren,
      matchRoutes,
    }),

  ],
  tracesSampleRate: 1.0,
});


// Call this AFTER Sentry.init()
const sentryCreateBrowserRouter = Sentry.wrapCreateBrowserRouterV7(
  createBrowserRouter,
);

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

## [Usage With `<Routes />` Component (Declarative Mode)](https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/v7.md#usage-with-routes--component-declarative-mode)

If you're using the `<Routes />` component to define your routes, update your `Sentry.browserTracingIntegration` to `Sentry.reactRouterV7BrowserTracingIntegration` inside `Sentry.init` and provide the required React hooks and router functions. Then, 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.

```javascript
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: "___PUBLIC_DSN___",
  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 wrapper is only needed at the top level of your app, unlike React Router v4/v5, which required wrapping every `<Route />` you wanted parametrized.

## [Usage With `useRoutes` Hook](https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/v7.md#usage-with-useroutes-hook)

If you specify your route definitions as an object to the [`useRoutes` hook](https://reactrouter.com/en/main/hooks/use-routes), update your `Sentry.browserTracingIntegration` to `Sentry.reactRouterV7BrowserTracingIntegration` inside `Sentry.init` and provide the required React hooks and router functions. Then, use `Sentry.wrapUseRoutesV7` to create a patched `useRoutes` hook that instruments your routes with Sentry.

##### Important

Call `wrapUseRoutesV7` outside of a React component, as in the example below. We also recommend that you assign the wrapped hook to a variable starting with `use`, as per [React's documentation](https://react.dev/learn/reusing-logic-with-custom-hooks#hook-names-always-start-with-use).

```javascript
import React from "react";

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

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


Sentry.init({
  dsn: "___PUBLIC_DSN___",
  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, unlike React Router v4/v5, which required wrapping every `<Route />` you wanted parametrized.

## [Static Route Manifest](https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/v7.md#static-route-manifest)

Available since: `v10.39.0`

When using [`patchRoutesOnNavigation`](https://reactrouter.com/api/data-routers/createBrowserRouter#optspatchroutesonnavigation) to dynamically load route definitions, the full route hierarchy isn't available to Sentry until each route is navigated to. This can cause transactions to receive incomplete or wildcard names (for example, `/users/*` instead of `/users/:userId`).

To ensure accurate transaction names, you can provide a static list of route patterns via the `lazyRouteManifest` option. When provided, Sentry uses this manifest as the primary source for determining transaction names without needing to wait for route modules to load.

Make sure to keep the `lazyRouteManifest` array in sync with your route definitions: if you add, remove, or change routes in your app, update this list accordingly. Any route that doesn't match a pattern in the manifest will fall back to the default behavior, which may result in incomplete transaction names until the route is visited. You can also include non-lazy routes in the manifest for convenience or consistency.

To use `lazyRouteManifest`, you need to set `enableAsyncRouteHandlers: true` in your `reactRouterV7BrowserTracingIntegration` configuration:

```javascript
import React from "react";
import {
  createRoutesFromChildren,
  matchRoutes,
  useLocation,
  useNavigationType,
} from "react-router";

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

Sentry.init({
  dsn: "___PUBLIC_DSN___",
  integrations: [
    Sentry.reactRouterV7BrowserTracingIntegration({
      useEffect: React.useEffect,
      useLocation,
      useNavigationType,
      createRoutesFromChildren,
      matchRoutes,

      enableAsyncRouteHandlers: true,
      lazyRouteManifest: [
        "/users",
        "/users/:userId",
        "/users/:userId/settings",
        "/dashboard",
        "/dashboard/analytics",
      ],

    }),
  ],
  tracesSampleRate: 1.0,
});
```

## [Set Up a Custom Error Boundary](https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/v7.md#set-up-a-custom-error-boundary)

When using `react-router`, errors thrown inside route elements will only be re-thrown in **development mode** while using [`strict mode`](https://react.dev/reference/react/StrictMode).\
In production, these errors won't surface unless captured manually. If you **don't** have a custom error boundary in place, `react-router` will create a default one that "swallows" all errors.\
Hence, to capture these errors with Sentry in production, we strongly recommend to implement a custom error boundary.

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

```jsx
// 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>
  );
}
```

## [Next Steps](https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/v7.md#next-steps)

* [Return to **Getting Started**](https://docs.sentry.io/platforms/javascript/guides/react/features.md)
* [Return to the main integrations page](https://docs.sentry.io/platforms/javascript/guides/react/features/react-router.md)
