React Router
React Router (v7) is a framework for building full-stack web apps and websites. Learn how to set it up with Sentry.
Library Mode
If you are using React Router in library mode, you can follow the instructions in the React Router library mode guide.
Limited Support
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.tsx
import * 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.tsx
import * 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.mjs
import * 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.tsx
import * 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.tsx
import 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").