---
title: "Hydrogen with React Router"
description: "Learn how to instrument your Hydrogen app on Shopify Oxygen and capture your first errors and traces."
url: https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router/
---

# Hydrogen with React Router | Sentry for Cloudflare

This guide applies to Hydrogen versions **2025.5.0 and later** that use React Router 7 (framework mode). For older versions of Hydrogen that use Remix v2, see our [Remix on Cloudflare guide](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-remix.md).

## [Prerequisites](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.md#prerequisites)

You need:

* A Sentry [account](https://sentry.io/signup/) and [project](https://docs.sentry.io/product/projects.md)
* Your Hydrogen application (v2025.5.0+), you want to host on Shopify Oxygen

## [Step 1: Install](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.md#step-1-install)

Choose the features you want to configure, and this guide will show you how:

Error Monitoring\[ ]Tracing\[ ]Session Replay\[ ]Logs\[ ]User Feedback

Want to learn more about these features?

* [**Issues**](https://docs.sentry.io/product/issues.md) (always enabled)
  <!-- -->
  :
  <!-- -->
  Sentry's core error monitoring product that automatically reports errors, uncaught exceptions, and unhandled rejections. If you have something that looks like an exception, Sentry can capture it.
* [**Tracing**](https://docs.sentry.io/product/tracing.md):
  <!-- -->
  Track software performance while seeing the impact of errors across multiple systems. For example, distributed tracing allows you to follow a request from the frontend to the backend and back.
* [**Session Replay**](https://docs.sentry.io/product/explore/session-replay/web.md):
  <!-- -->
  Get to the root cause of an issue faster by viewing a video-like reproduction of what was happening in the user's browser before, during, and after the problem.
* [**Logs**](https://docs.sentry.io/product/explore/logs.md):
  <!-- -->
  Centralize and analyze your application logs to correlate them with errors and performance issues. Search, filter, and visualize log data to understand what's happening in your applications.
* [**User Feedback**](https://docs.sentry.io/product/user-feedback.md):
  <!-- -->
  Collect feedback directly from users when they encounter errors, allowing them to describe what happened and provide context that helps you understand and resolve issues faster.

### [Install the Sentry SDK](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.md#install-the-sentry-sdk)

Run the command for your preferred package manager to add the React Router and Cloudflare SDK:

```bash
npm install @sentry/react-router @sentry/cloudflare --save
```

## [Step 2: Configure](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.md#step-2-configure)

### [Configure Client-side Sentry](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.md#configure-client-side-sentry)

Initialize Sentry in your `entry.client.tsx` file:

`app/entry.client.tsx`

```tsx
import { HydratedRouter } from "react-router/dom";
import * as Sentry from "@sentry/react-router/cloudflare";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";

Sentry.init({
  dsn: "___PUBLIC_DSN___",

  // Adds request headers and IP for users, for more info visit:
  // https://docs.sentry.io/platforms/javascript/guides/react-router/configuration/options/#sendDefaultPii
  sendDefaultPii: true,

  integrations: [
    // ___PRODUCT_OPTION_START___ performance
    // Registers and configures the Tracing integration,
    // which automatically instruments your application to monitor its
    // performance, including custom React Router routing instrumentation
    Sentry.reactRouterTracingIntegration(),
    // ___PRODUCT_OPTION_END___ performance
    // ___PRODUCT_OPTION_START___ session-replay
    // Registers the Replay integration,
    // which automatically captures Session Replays
    Sentry.replayIntegration(),
    // ___PRODUCT_OPTION_END___ session-replay
    // ___PRODUCT_OPTION_START___ user-feedback
    Sentry.feedbackIntegration({
      // Additional SDK configuration goes in here, for example:
      colorScheme: "system",
    }),
    // ___PRODUCT_OPTION_END___ user-feedback
  ],
  // ___PRODUCT_OPTION_START___ logs

  // Enable logs to be sent to Sentry
  enableLogs: true,
  // ___PRODUCT_OPTION_END___ logs
  // ___PRODUCT_OPTION_START___ performance

  // Set tracesSampleRate to 1.0 to capture 100%
  // of transactions for tracing.
  // We recommend adjusting this value in production
  // Learn more at
  // https://docs.sentry.io/platforms/javascript/guides/react-router/configuration/options/#traces-sample-rate
  tracesSampleRate: 1.0,
  // ___PRODUCT_OPTION_END___ performance
  // ___PRODUCT_OPTION_START___ session-replay

  // Capture Replay for 10% of all sessions,
  // plus 100% of sessions with an error
  // Learn more at
  // https://docs.sentry.io/platforms/javascript/guides/react-router/session-replay/configuration/#general-integration-configuration
  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,
  // ___PRODUCT_OPTION_END___ session-replay
});

startTransition(() => {
  hydrateRoot(
    document,
    <StrictMode>
      <HydratedRouter />
    </StrictMode>,
  );
});
```

### [Configure Server-side Sentry](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.md#configure-server-side-sentry)

First, create an `instrument.server.mjs` file to initialize Sentry on the server:

`instrument.server.mjs`

```js
import * as Sentry from "@sentry/react-router";

Sentry.init({
  dsn: "___PUBLIC_DSN___",

  // Adds request headers and IP for users, for more info visit:
  // https://docs.sentry.io/platforms/javascript/guides/react-router/configuration/options/#sendDefaultPii
  sendDefaultPii: true,
  // ___PRODUCT_OPTION_START___ logs

  // Enable logs to be sent to Sentry
  enableLogs: true,
  // ___PRODUCT_OPTION_END___ logs
  // ___PRODUCT_OPTION_START___ performance

  // Set tracesSampleRate to 1.0 to capture 100%
  // of transactions for tracing.
  // We recommend adjusting this value in production
  // Learn more at
  // https://docs.sentry.io/platforms/javascript/guides/react-router/configuration/options/#tracesSampleRate
  tracesSampleRate: 1.0,
  // ___PRODUCT_OPTION_END___ performance
});
```

Next, update your `server.ts` file to use the `wrapRequestHandler` method from `@sentry/cloudflare`:

`server.ts`

```ts
import { wrapRequestHandler } from "@sentry/cloudflare";
// ...other imports

/**
 * Export a fetch handler in module format.
 */
export default {
  async fetch(
    request: Request,
    env: Env,
    executionContext: ExecutionContext
  ): Promise<Response> {
    return wrapRequestHandler(
      {
        options: {
          dsn: "___PUBLIC_DSN___",
          // ___PRODUCT_OPTION_START___ performance
          tracesSampleRate: 1.0,
          // ___PRODUCT_OPTION_END___ performance
          // ___PRODUCT_OPTION_START___ logs
          enableLogs: true,
          // ___PRODUCT_OPTION_END___ logs
          sendDefaultPii: true,
        },
        request: request as any,
        context: executionContext,
      },
      async () => {
        // Your existing Hydrogen server logic
        const handleRequest = createRequestHandler({
          // @ts-ignore
          build: await import("virtual:react-router/server-build"),
          mode: process.env.NODE_ENV,
          getLoadContext: (): AppLoadContext => ({
            // your load context
          }),
        });

        return handleRequest(request);
      }
    );
  },
};
```

### [Enable Distributed Tracing](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.md#enable-distributed-tracing)

Update your `entry.server.tsx` file to inject trace meta tags:

`app/entry.server.tsx`

```tsx
import "./instrument.server";
import { HandleErrorFunction, ServerRouter } from "react-router";
import type { EntryContext } from "@shopify/remix-oxygen";
import { renderToReadableStream } from "react-dom/server";
import * as Sentry from "@sentry/react-router/cloudflare";

async function handleRequest(
  request: Request,
  responseStatusCode: number,
  responseHeaders: Headers,
  reactRouterContext: EntryContext,
) {
  const body = Sentry.injectTraceMetaTags(
    await renderToReadableStream(
      <ServerRouter context={reactRouterContext} url={request.url} />,
      {
        signal: request.signal,
      },
    ),
  );

  responseHeaders.set("Content-Type", "text/html");

  return new Response(body, {
    headers: responseHeaders,
    status: responseStatusCode,
  });
}

export const handleError: HandleErrorFunction = (error, { request }) => {
  // React Router may abort some interrupted requests, don't log those
  if (!request.signal.aborted) {
    Sentry.captureException(error);
    console.error(error);
  }
};

export default Sentry.wrapSentryHandleRequest(handleRequest);
```

## [Step 3: Add Readable Stack Traces With Source Maps (Optional)](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.md#step-3-add-readable-stack-traces-with-source-maps-optional)

The stack traces in your Sentry errors probably won't look like your actual code without unminifying them. To fix this, upload your source maps to Sentry.

First, update `vite.config.ts` to include the `sentryReactRouter` plugin, making sure to pass both the Vite and Sentry configurations to it:

`vite.config.ts`

```ts
import { reactRouter } from "@react-router/dev/vite";
import { hydrogen } from "@shopify/hydrogen/vite";
import { oxygen } from "@shopify/mini-oxygen/vite";
import { defineConfig } from "vite";
import { sentryReactRouter } from "@sentry/react-router";

export default defineConfig((config) => ({
  plugins: [
    hydrogen(),
    oxygen(),
    reactRouter(),
    sentryReactRouter(
      {
        org: "___ORG_SLUG___",
        project: "___PROJECT_SLUG___",

        // An auth token is required for uploading source maps;
        // store it in an environment variable to keep it secure.
        authToken: process.env.SENTRY_AUTH_TOKEN,
      },
      config
    ),
    // ... other plugins
  ],
}));
```

Since the `buildEnd` hook will not be executed for Hydrogen, you need to manually upload source maps using the [Sentry CLI](https://docs.sentry.io/cli.md) instead:

```bash
# Inject debug IDs
sentry-cli sourcemaps inject /path/to/build/dir
# Upload sourcemaps
sentry-cli sourcemaps upload /path/to/build/dir
```

## [Step 4: Verify Your Setup](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.md#step-4-verify-your-setup)

Let's test your setup and confirm that Sentry is working correctly and sending data to your Sentry project.

### [Issues](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.md#issues)

To verify that Sentry captures errors and creates issues in your Sentry project, throw an error in a loader:

`app/routes/sentry-test.tsx`

```tsx
import type { Route } from "./+types/sentry-test";

export async function loader() {
  throw new Error("My first Sentry error!");
}

export default function SentryTestPage() {
  return <div>Loading this page will throw an error</div>;
}
```

Open the `/sentry-test` route in your browser, and you should trigger an error.

##### Important

Errors triggered from within your browser's developer tools (like the browser console) are sandboxed, so they will not trigger Sentry's error monitoring.

### [Tracing](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.md#tracing)

To test your tracing configuration, update the previous code snippet by starting a trace to measure the time it takes for the execution of your code:

`app/routes/sentry-test.tsx`

```tsx
import * as Sentry from "@sentry/react-router/cloudflare";
import type { Route } from "./+types/sentry-test";

export async function loader() {
  return Sentry.startSpan(
    {
      op: "test",
      name: "My First Test Trace",
    },
    () => {
      throw new Error("My first Sentry error!");
    },
  );
}

export default function SentryTestPage() {
  return <div>Loading this page will throw an error</div>;
}
```

Open the `/sentry-test` route in your browser. You should start a trace and trigger an error.

### [Logs NEW](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.md#logs-)

To verify that Sentry catches your logs, add some log statements to your application:

```javascript
Sentry.logger.info("User example action completed");

Sentry.logger.warn("Slow operation detected", {
  operation: "data_fetch",
  duration: 3500,
});

Sentry.logger.error("Validation failed", {
  field: "email",
  reason: "Invalid email",
});
```

### [View Captured Data in Sentry](https://docs.sentry.io/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router.md#view-captured-data-in-sentry)

Now, head over to your project on [Sentry.io](https://sentry.io) to view the collected data (it takes a couple of moments for the data to appear).

Need help locating the captured errors in your Sentry project?

* Open the
  <!-- -->
  [**Issues**](https://sentry.io/orgredirect/organizations/:orgslug/issues/)
  <!-- -->
  page and select an error from the issues list to view the full details and context of this error. For more details, see this
  <!-- -->
  [interactive walkthrough](https://docs.sentry.io/product/sentry-basics/integrate-frontend/generate-first-error.md#ui-walkthrough).
* Open the
  <!-- -->
  [**Traces**](https://sentry.io/orgredirect/organizations/:orgslug/explore/traces/)
  <!-- -->
  page and select a trace to reveal more information about each span, its duration, and any errors. For an interactive UI walkthrough, click
  <!-- -->
  [here](https://docs.sentry.io/product/sentry-basics/distributed-tracing/generate-first-error.md#ui-walkthrough).
* Open the
  <!-- -->
  [**Replays**](https://sentry.io/orgredirect/organizations/:orgslug/replays/)
  <!-- -->
  page and select an entry from the list to get a detailed view where you can replay the interaction and get more information to help you troubleshoot.
* Open the
  <!-- -->
  [**Logs**](https://sentry.io/orgredirect/organizations/:orgslug/explore/logs/)
  <!-- -->
  page and filter by service, environment, or search keywords to view log entries from your application. For an interactive UI walkthrough, click
  <!-- -->
  [here](https://docs.sentry.io/product/explore/logs.md#overview).
* Open the
  <!-- -->
  [**User Feedback**](https://sentry.io/orgredirect/organizations/:orgslug/feedback/)
  <!-- -->
  page and click on individual feedback to see more details all in one view. For more information, click [here](https://docs.sentry.io/product/user-feedback.md).

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

At this point, you should have integrated Sentry into your React Router Framework application and should already be sending data to your Sentry project.

Now's a good time to customize your setup and look into more advanced topics. Our next recommended steps for you are:

* Explore [practical guides](https://docs.sentry.io/guides.md) on what to monitor, log, track, and investigate after setup
* Learn how to [manually capture errors](https://docs.sentry.io/platforms/javascript/guides/cloudflare/usage.md)
* Continue to [customize your configuration](https://docs.sentry.io/platforms/javascript/guides/cloudflare/configuration.md)
* Make use of [React Router-specific features](https://docs.sentry.io/platforms/javascript/guides/react-router/features.md)
* Get familiar with [Sentry's product features](https://docs.sentry.io/product.md) like tracing, insights, and alerts

Are you having problems setting up the SDK?

* Find various topics in [Troubleshooting](https://docs.sentry.io/platforms/javascript/guides/cloudflare/troubleshooting.md)
* [Get support](https://sentry.zendesk.com/hc/en-us/)
