React Router v7 (framework mode)
React Router v7 is a framework for building full-stack web apps and websites. Learn how to set it up with Sentry.
Looking for library mode?
If you are using React Router in library mode, you can follow the instructions in the React guide here.
SDK Limitations
We do not yet have a dedicated SDK for React Router in framework mode. This guide demonstrates how to setup error monitoring and basic performance tracing using the @sentry/react and @sentry/node packages instead.
Sentry captures data by using an SDK within your application’s runtime.
npm install @sentry/react @sentry/node @sentry/profiling-node
npm install @sentry/react @sentry/node
React Router exposes two hooks in your app folder (entry.client.tsx and entry.server.tsx). If you do not see these two files, expose them with the following command:
npx react-router reveal
Initialize the Sentry React SDK in your entry.client.tsx file:
entry.client.tsximport * as Sentry from "@sentry/react";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
import { HydratedRouter } from "react-router/dom";
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
Sentry.browserTracingIntegration(),
Sentry.replayIntegration(),
],
tracesSampleRate: 1.0, // Capture 100% of the transactions
// Set `tracePropagationTargets` to declare which URL(s) should have trace propagation enabled
tracePropagationTargets: [/^\//, /^https:\/\/yourserver\.io\/api/],
// Capture Replay for 10% of all sessions,
// plus 100% of sessions with an error
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
});
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<HydratedRouter />
</StrictMode>
);
});
Now, update your app/root.tsx file to report any unhandled errors from your error boundary:
app/root.tsximport * as Sentry from "@sentry/react";
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
let message = "Oops!";
let details = "An unexpected error occurred.";
let stack: string | undefined;
if (isRouteErrorResponse(error)) {
message = error.status === 404 ? "404" : "Error";
details =
error.status === 404
? "The requested page could not be found."
: error.statusText || details;
} else if (error && error instanceof Error) {
// you only want to capture non 404-errors that reach the boundary
+ Sentry.captureException(error);
if (import.meta.env.DEV) {
details = error.message;
stack = error.stack;
}
}
return (
<main>
<h1>{message}</h1>
<p>{details}</p>
{stack && (
<pre>
<code>{stack}</code>
</pre>
)}
</main>
);
}
// ...
Create an instrument.server.mjs file in the root of your app:
instrument.server.mjsimport * as Sentry from "@sentry/node";
import { nodeProfilingIntegration } from '@sentry/profiling-node';
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [nodeProfilingIntegration()],
tracesSampleRate: 1.0, // Capture 100% of the transactions
profilesSampleRate: 1.0, // profile every transaction
});
In your entry.server.tsx file, export the handleError function:
entry.server.tsximport * as Sentry from "@sentry/node";
import { type HandleErrorFunction } from "react-router";
export const handleError: HandleErrorFunction = (error, { request }) => {
// React Router may abort some interrupted requests, report those
if (!request.signal.aborted) {
+ Sentry.captureException(error);
// make sure to still log the error so you can see it
console.error(error);
}
};
// ... rest of your server entry
Since React Router is running in ESM mode, you need to use the --import command line options to load our server-side instrumentation module before the application starts. Update the start and dev script to include the instrumentation file:
package.json"scripts": {
"dev": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router dev",
"start": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js",
}
By default, React Router will minify your JavaScript and CSS files in production. This makes it difficult to debug errors. To make debugging easier, you can generate source maps and upload them to Sentry.
We recommend using Sentry's Vite plugin to upload sourcemaps.
Please refer to the Source Maps Documentation, for more information.
For more advanced configuration, you can use sentry-cli directly to upload source maps.
This snippet includes an intentional error, so you can test that everything is working as soon as you set it up.
Throw an error in a loader to verify that Sentry is working. After opening this route in your browser, you should see two errors in the Sentry issue stream, one captured from the server and one captured from the client.
error.tsximport type { Route } from "./+types/example-page";
export async function loader() {
throw new Error("some error thrown in a loader");
}
export default function ExamplePage() {
return <div>Loading this page will throw an error</div>;
}
Learn more about manually capturing an error or message in our Usage documentation.
To view and resolve the recorded error, log into sentry.io and select your project. Clicking on the error's title will open a page where you can see detailed information and mark it as resolved.
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").