Skip to content

docs(js): Add docs for Hydrogen with RR7 #14613

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
---
title: Hydrogen with React Router
description: Learn how to use the Sentry React Router SDK to instrument your Hydrogen app (versions 2025.5.0+).
---

<Alert level="info" title="Hydrogen Version">

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 the [Remix guide](/platforms/javascript/guides/cloudflare/frameworks/hydrogen-remix/).

</Alert>

Starting from Hydrogen version 2025.5.0, Shopify switched from Remix v2 to React Router 7 (framework mode). You can use the Sentry React Router SDK with Cloudflare support to add Sentry instrumentation to your Hydrogen app.

## Installing Sentry React Router and Cloudflare SDKs

First, install the Sentry React Router and Cloudflare SDKs with your package manager:

```bash {tabTitle:npm}
npm install @sentry/react-router @sentry/cloudflare --save
```

```bash {tabTitle:yarn}
yarn add @sentry/react-router @sentry/cloudflare
```

```bash {tabTitle:pnpm}
pnpm add @sentry/react-router @sentry/cloudflare
```

## Instrumenting Your Server

Create an `instrument.server.mjs` file to initialize Sentry on the server:

```js {filename:instrument.server.mjs}
import * as Sentry from "@sentry/react-router";

Sentry.init({
dsn: "YOUR_DSN_HERE",
// 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,
tracesSampleRate: 1.0,
});
```

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

```ts {filename:server.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: "YOUR_DSN_HERE",
tracesSampleRate: 1.0,
},
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);
}
);
},
};
```

## Instrumenting Your Client

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

```tsx {filename:app/entry.client.tsx}
import { HydratedRouter } from 'react-router/dom';
import * as Sentry from '@sentry/react-router/cloudflare';
import { StrictMode, startTransition } from 'react';
import { hydrateRoot } from 'react-dom/client';

Sentry.init({
dsn: "___PUBLIC_DSN___",
integrations: [Sentry.reactRouterTracingIntegration()],
tracesSampleRate: 1.0,
});

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

## Server-Side Rendering with Trace Injection

To enable distributed tracing, wrap your `handleRequest` function in your `entry.server.tsx` file and inject trace meta tags:

```tsx {filename:app/entry.server.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);
```

## Configuration

### Vite Configuration

Add the Sentry plugin to your `vite.config.ts`:

```ts {filename:vite.config.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: "your-org-slug",
project: "your-project-slug",
authToken: process.env.SENTRY_AUTH_TOKEN,
}, config),
// ... other plugins
],
}));
```

### Build Configuration

Add the `buildEnd` hook to your `react-router.config.ts`:

```ts {filename:react-router.config.ts}
import type {Config} from '@react-router/dev/config';
import { sentryOnBuildEnd } from '@sentry/react-router';

export default {
appDirectory: 'app',
buildDirectory: 'dist',
ssr: true,
buildEnd: async ({ viteConfig, reactRouterConfig, buildManifest }) => {
// Call this at the end of the hook
(await sentryOnBuildEnd({ viteConfig, reactRouterConfig, buildManifest }));
}
} satisfies Config;
```
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
---
title: Hydrogen Guide
description: "Learn how to use the Sentry Remix SDK to instrument your Hydrogen app."
title: Hydrogen with Remix (Legacy)
description: Learn how to use the Sentry Remix SDK to instrument your Hydrogen app (versions before 2025.5.0).
---

If you're using the Shopify's Hydrogen framework, you can use the Sentry Remix SDK to add Sentry instrumentation to your app.
<Alert level="info" title="Hydrogen Version">

## 1. Installing Sentry Remix and Clouflare SDKs
This guide applies to Hydrogen versions **before 2025.5.0** that use Remix v2. For newer versions of Hydrogen (2025.5.0+) that use React Router 7, see the [React Router guide](/platforms/javascript/guides/cloudflare/frameworks/hydrogen-react-router/).

</Alert>

If you're using Shopify's Hydrogen framework with Remix v2, you can use the Sentry Remix SDK to add Sentry instrumentation to your app.

## Installing Sentry Remix and Cloudflare SDKs

First, install the Sentry Remix and Cloudflare SDKs with your package manager:

Expand All @@ -21,13 +27,14 @@ yarn add @sentry/remix @sentry/cloudflare
pnpm add @sentry/remix @sentry/cloudflare
```

## 2. Instrumenting Your Server
## Instrumenting Your Server

Then update your `server.ts` file to use the `wrapRequestHandler` method:
Update your `server.ts` file to use the `wrapRequestHandler` method from `@sentry/cloudflare/request` and `instrumentBuild` from `@sentry/remix/cloudflare`:

```ts {filename:server.ts}
import { wrapRequestHandler } from "@sentry/cloudflare/request";
import { instrumentBuild } from "@sentry/remix/cloudflare";
import { createRequestHandler } from "@remix-run/cloudflare";
// Virtual entry point for the app
import * as remixBuild from 'virtual:remix/server-build';

Expand All @@ -53,33 +60,45 @@ export default {
async () => {
// Instrument your server build with Sentry
// and use the instrumented build inside the fetch handler
const instrumentedBuild = instrumentBuild(remixBuild)
const instrumentedBuild = instrumentBuild(remixBuild);

const handleRequest = createRequestHandler({
build: instrumentedBuild,
mode: process.env.NODE_ENV,
getLoadContext: (): AppLoadContext => ({
// your load context
}),
});

// request handling logic
return handleRequest(request);
}
);
},
};
```

## 3. Instrumenting Your Client
## Instrumenting Your Client

Wrap your Remix root component using `withSentry`:

```tsx {filename:root.tsx}
import { withSentry } from "@sentry/remix/cloudflare";
```tsx {filename:app/root.tsx}
import * as Sentry from "@sentry/remix/cloudflare";
import { useEffect } from "react";
import { useLocation, useMatches } from "@remix-run/react";

function App({ children }) {
return <>{children}</>;
function App() {
return (
// Your app content
);
}

// Pass `useEffect`, `useLocation` and `useMatches` hooks to `withSentry`
export default withSentry(App, useEffect, useLocation, useMatches);
export default Sentry.withSentry(App, useEffect, useLocation, useMatches);
```

Finally, update your `entry.client.tsx` file to initialize Sentry SDK on the client:

```tsx {filename:entry.client.tsx}
```tsx {filename:app/entry.client.tsx}
import * as Sentry from "@sentry/remix";

Sentry.init({
Expand Down