This SDK is currently in **beta**. Beta features are still in progress and may
have bugs. Please reach out on
[GitHub](https://github.com/getsentry/sentry-javascript/issues/new/choose) if
@@ -18,7 +18,7 @@ categories:
- If you are using React Router in library mode, you can follow the instructions in the [React guide here](/platforms/javascript/guides/react/features/react-router/v7).
+If you are using React Router in library mode, you can follow the instructions in the [React guide here](/platforms/javascript/guides/react/features/react-router/v7).
@@ -36,25 +36,25 @@ Sentry captures data by using an SDK within your application's runtime.
"user-feedback",
"logs",
{
- id: 'profiling',
- checked: false
- }
+ id: "profiling",
+ checked: false,
+ },
]}
/>
- ```bash {tabTitle:npm}
- npm install @sentry/react-router @sentry/profiling-node
- ```
+```bash {tabTitle:npm}
+npm install @sentry/react-router @sentry/profiling-node
+```
- ```bash {tabTitle:yarn}
- yarn add @sentry/react-router @sentry/profiling-node
- ```
+```bash {tabTitle:yarn}
+yarn add @sentry/react-router @sentry/profiling-node
+```
- ```bash {tabTitle:pnpm}
- pnpm add @sentry/react-router @sentry/profiling-node
- ```
+```bash {tabTitle:pnpm}
+pnpm add @sentry/react-router @sentry/profiling-node
+```
@@ -63,18 +63,20 @@ Sentry captures data by using an SDK within your application's runtime.
npm install @sentry/react-router
```
- ```bash {tabTitle:yarn}
- yarn add @sentry/react-router
- ```
+```bash {tabTitle:yarn}
+yarn add @sentry/react-router
+```
+
+```bash {tabTitle:pnpm}
+pnpm add @sentry/react-router
+```
- ```bash {tabTitle:pnpm}
- pnpm add @sentry/react-router
- ```
## Configure
### Expose Hooks
+
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:
@@ -94,11 +96,11 @@ Initialize the Sentry React SDK in your `entry.client.tsx` file:
+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
+ Sentry.reactRouterTracingIntegration(),
@@ -190,38 +192,41 @@ export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
Automatic server-side instrumentation is currently only supported on:
- **Node 20:** Version \<20.19
- **Node 22:** Version \<22.12
-
-
- If you are on a different version please make use of our manual server wrappers.
-
- For server loaders use `wrapServerLoader`:
+
+If you are on a different version please make use of our manual server wrappers.
+
+For server loaders use `wrapServerLoader`:
+
```ts
-import * as Sentry from '@sentry/react-router';
+import * as Sentry from "@sentry/react-router";
export const loader = Sentry.wrapServerLoader(
{
- name: 'Load Some Data',
- description: 'Loads some data from the db',
+ name: "Load Some Data",
+ description: "Loads some data from the db",
},
async ({ params }) => {
// ... your loader logic
}
);
```
- For server actions use `wrapServerAction`:
+
+For server actions use `wrapServerAction`:
+
```ts
-import * as Sentry from '@sentry/react-router';
+import * as Sentry from "@sentry/react-router";
export const action = Sentry.wrapServerAction(
{
- name: 'Submit Form Data',
- description: 'Processes form submission data',
+ name: "Submit Form Data",
+ description: "Processes form submission data",
},
async ({ request }) => {
// ... your action logic
}
);
```
+
Create an `instrument.server.mjs` file in the root of your app:
@@ -229,12 +234,12 @@ Create an `instrument.server.mjs` file in the root of your app:
```js {filename: instrument.server.mjs}
import * as Sentry from "@sentry/react-router";
// ___PRODUCT_OPTION_START___ profiling
-import { nodeProfilingIntegration } from '@sentry/profiling-node';
+import { nodeProfilingIntegration } from "@sentry/profiling-node";
// ___PRODUCT_OPTION_END___ profiling
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,
@@ -244,7 +249,7 @@ Sentry.init({
_experiments: { enableLogs: true },
// ___PRODUCT_OPTION_END___ logs
// ___PRODUCT_OPTION_START___ profiling
-
+
integrations: [nodeProfilingIntegration()],
// ___PRODUCT_OPTION_END___ profiling
// ___PRODUCT_OPTION_START___ performance
@@ -288,76 +293,80 @@ export const handleError: HandleErrorFunction = (error, { request }) => {
If you need to update the logic of your `handleRequest` function you'll need to include the provided Sentry helper functions (`getMetaTagTransformer` and `wrapSentryHandleRequest`) manually:
-
- ```tsx {1-4, 44-45, 69-70}
- import { getMetaTagTransformer, wrapSentryHandleRequest } from '@sentry/react-router';
- // ... other imports
-
- const handleRequest = function handleRequest(
- request: Request,
- responseStatusCode: number,
- responseHeaders: Headers,
- routerContext: EntryContext,
- _loadContext: AppLoadContext,
- ): Promise {
- return new Promise((resolve, reject) => {
- let shellRendered = false;
- const userAgent = request.headers.get('user-agent');
-
- // Determine if we should use onAllReady or onShellReady
- const isBot = typeof userAgent === 'string' && botRegex.test(userAgent);
- const isSpaMode = !!(routerContext as { isSpaMode?: boolean }).isSpaMode;
-
- const readyOption = isBot || isSpaMode ? 'onAllReady' : 'onShellReady';
-
- const { pipe, abort } = renderToPipeableStream(
- ,
- {
- [readyOption]() {
- shellRendered = true;
- const body = new PassThrough();
-
- const stream = createReadableStreamFromReadable(body);
-
- responseHeaders.set('Content-Type', 'text/html');
-
- resolve(
- new Response(stream, {
- headers: responseHeaders,
- status: responseStatusCode,
- }),
- );
-
- // this enables distributed tracing between client and server
- pipe(getMetaTagTransformer(body));
- },
- onShellError(error: unknown) {
- reject(error);
- },
- onError(error: unknown) {
- // eslint-disable-next-line no-param-reassign
- responseStatusCode = 500;
- // Log streaming rendering errors from inside the shell. Don't log
- // errors encountered during initial shell rendering since they'll
- // reject and get logged in handleDocumentRequest.
- if (shellRendered) {
- // eslint-disable-next-line no-console
- console.error(error);
- }
- },
+
+```tsx {1-4, 44-45, 69-70}
+import {
+ getMetaTagTransformer,
+ wrapSentryHandleRequest,
+} from "@sentry/react-router";
+// ... other imports
+
+const handleRequest = function handleRequest(
+ request: Request,
+ responseStatusCode: number,
+ responseHeaders: Headers,
+ routerContext: EntryContext,
+ _loadContext: AppLoadContext
+): Promise {
+ return new Promise((resolve, reject) => {
+ let shellRendered = false;
+ const userAgent = request.headers.get("user-agent");
+
+ // Determine if we should use onAllReady or onShellReady
+ const isBot = typeof userAgent === "string" && botRegex.test(userAgent);
+ const isSpaMode = !!(routerContext as { isSpaMode?: boolean }).isSpaMode;
+
+ const readyOption = isBot || isSpaMode ? "onAllReady" : "onShellReady";
+
+ const { pipe, abort } = renderToPipeableStream(
+ ,
+ {
+ [readyOption]() {
+ shellRendered = true;
+ const body = new PassThrough();
+
+ const stream = createReadableStreamFromReadable(body);
+
+ responseHeaders.set("Content-Type", "text/html");
+
+ resolve(
+ new Response(stream, {
+ headers: responseHeaders,
+ status: responseStatusCode,
+ })
+ );
+
+ // this enables distributed tracing between client and server
+ pipe(getMetaTagTransformer(body));
+ },
+ onShellError(error: unknown) {
+ reject(error);
+ },
+ onError(error: unknown) {
+ // eslint-disable-next-line no-param-reassign
+ responseStatusCode = 500;
+ // Log streaming rendering errors from inside the shell. Don't log
+ // errors encountered during initial shell rendering since they'll
+ // reject and get logged in handleDocumentRequest.
+ if (shellRendered) {
+ // eslint-disable-next-line no-console
+ console.error(error);
+ }
},
- );
+ }
+ );
- // Abort the rendering stream after the `streamTimeout`
- setTimeout(abort, streamTimeout);
- });
- };
-
- // wrap the default export
- export default wrapSentryHandleRequest(handleRequest);
+ // Abort the rendering stream after the `streamTimeout`
+ setTimeout(abort, streamTimeout);
+ });
+};
+
+// wrap the default export
+export default wrapSentryHandleRequest(handleRequest);
+
+// ... rest of your entry.server.ts file
+```
- // ... rest of your entry.server.ts file
- ```
### Update Scripts
@@ -369,8 +378,8 @@ Update the `start` and `dev` script to include the instrumentation file:
```json {filename: 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",
+"dev": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router dev",
+"start": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js",
}
```
@@ -388,7 +397,7 @@ If you're deploying to platforms like **Vercel** or **Netlify** where setting th
- When importing the instrumentation file directly in `entry.server.tsx` instead of using the `--import` flag, automatic instrumentation will be incomplete and you'll miss automatically captured spans and traces for some of your application's server-side operations. This approach should only be used when the `NODE_OPTIONS` approach is not available on your hosting platform.
+When importing the instrumentation file directly in `entry.server.tsx` instead of using the `--import` flag, automatic instrumentation will be incomplete and you'll miss automatically captured spans and traces for some of your application's server-side operations. This approach should only be used when the `NODE_OPTIONS` approach is not available on your hosting platform.
@@ -396,8 +405,6 @@ If you're deploying to platforms like **Vercel** or **Netlify** where setting th
Update `vite.config.ts` to include the `sentryReactRouter` plugin, making sure to pass both the Vite and Sentry configurations to it:
-
-
```typescript {filename: vite.config.ts} {diff}
import { reactRouter } from '@react-router/dev/vite';
import { sentryReactRouter, type SentryReactRouterBuildOptions } from '@sentry/react-router';
@@ -407,8 +414,9 @@ const sentryConfig: SentryReactRouterBuildOptions = {
org: "___ORG_SLUG___",
project: "___PROJECT_SLUG___",
- // An auth token is required for uploading source maps.
- authToken: "___ORG_AUTH_TOKEN___"
+ // 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,
// ...
};
@@ -419,18 +427,26 @@ export default defineConfig(config => {
});
```
+To keep your auth token secure, always store it in an environment variable instead of directly in your files:
+
+
+
+```bash {filename:.env}
+SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___
+```
+
Include the `sentryOnBuildEnd` hook in `react-router.config.ts`:
```typescript {filename: react-router.config.ts} {diff}
-import type { Config } from '@react-router/dev/config';
-import { sentryOnBuildEnd } from '@sentry/react-router';
+import type { Config } from "@react-router/dev/config";
+import { sentryOnBuildEnd } from "@sentry/react-router";
export default {
ssr: true,
buildEnd: async ({ viteConfig, reactRouterConfig, buildManifest }) => {
// ...
// Call this at the end of the hook
-+ await sentryOnBuildEnd({ viteConfig, reactRouterConfig, buildManifest });
++ (await sentryOnBuildEnd({ viteConfig, reactRouterConfig, buildManifest }));
},
} satisfies Config;
```
@@ -450,13 +466,8 @@ export async function loader() {
}
export default function ExamplePage() {
- return (
-
- Loading this page will throw an error
-
- );
+ return Loading this page will throw an error
;
}
-
```
diff --git a/docs/platforms/javascript/guides/solidstart/index.mdx b/docs/platforms/javascript/guides/solidstart/index.mdx
index e97050c79dddc0..b37eaf99f4b0cf 100644
--- a/docs/platforms/javascript/guides/solidstart/index.mdx
+++ b/docs/platforms/javascript/guides/solidstart/index.mdx
@@ -9,7 +9,7 @@ categories:
## Install
-Sentry captures data by using an SDK within your application’s runtime.
+Sentry captures data by using an SDK within your application's runtime.
```bash {tabTitle:npm}
npm install @sentry/solidstart --save
@@ -31,30 +31,29 @@ Initialize the Sentry SDK in your `src/entry-client.tsx` file.
If you're using Solid Router, add the `solidRouterBrowserTracingIntegration` to collect meaningful performance data about the health of your page loads and associated requests.
-
```jsx {filename:src/entry-client.tsx}
-import * as Sentry from '@sentry/solidstart';
-import { solidRouterBrowserTracingIntegration } from '@sentry/solidstart/solidrouter';
-import { mount, StartClient } from '@solidjs/start/client';
+import * as Sentry from "@sentry/solidstart";
+import { solidRouterBrowserTracingIntegration } from "@sentry/solidstart/solidrouter";
+import { mount, StartClient } from "@solidjs/start/client";
Sentry.init({
- dsn: '___PUBLIC_DSN___',
-
+ dsn: "___PUBLIC_DSN___",
+
// Adds request headers and IP for users, for more info visit:
// https://docs.sentry.io/platforms/javascript/guides/solidstart/configuration/options/#sendDefaultPii
sendDefaultPii: true,
-
+
integrations: [solidRouterBrowserTracingIntegration()],
tracesSampleRate: 1.0, // Capture 100% of the transactions
});
-mount(() => , document.getElementById('app'));
+mount(() => , document.getElementById("app"));
```
- Depending on the configuration of your SolidStart project, the file structure may differ from the code listed on this page.
- For example, for JavaScript projects files end in `.js` and `.jsx` while we use TypeScript snippets here ending in `.ts` and `.tsx`.
+Depending on the configuration of your SolidStart project, the file structure may differ from the code listed on this page.
+For example, for JavaScript projects files end in `.js` and `.jsx` while we use TypeScript snippets here ending in `.ts` and `.tsx`.
@@ -63,15 +62,15 @@ mount(() => , document.getElementById('app'));
Create an instrument file `instrument.server.ts` in your `src` folder. In this file, initialize the Sentry SDK for your server.
```javascript {filename:src/instrument.server.ts}
-import * as Sentry from '@sentry/solidstart';
+import * as Sentry from "@sentry/solidstart";
Sentry.init({
- dsn: '___PUBLIC_DSN___',
-
+ dsn: "___PUBLIC_DSN___",
+
// Adds request headers and IP for users, for more info visit:
// https://docs.sentry.io/platforms/javascript/guides/solidstart/configuration/options/#sendDefaultPii
sendDefaultPii: true,
-
+
tracesSampleRate: 1.0, // Capture 100% of the transactions
});
```
@@ -79,8 +78,8 @@ Sentry.init({
Wrap your SolidStart config with `withSentry`, so this file gets added to your build output. With the default server preset, you can find the file here: `.output/server/instrument.server.mjs`.
```javascript {filename:app.config.ts} {5-12}
-import { withSentry } from '@sentry/solidstart';
-import { defineConfig } from '@solidjs/start/config';
+import { withSentry } from "@sentry/solidstart";
+import { defineConfig } from "@solidjs/start/config";
export default defineConfig(
withSentry(
@@ -90,7 +89,7 @@ export default defineConfig(
{
/* Your Sentry build-time config (such as source map upload options) */
}
- ),
+ )
);
```
@@ -101,8 +100,8 @@ The Sentry SDK provides [middleware lifecycle](https://docs.solidjs.com/solid-st
Complete the setup by adding `sentryBeforeResponseMiddleware` to your `src/middleware.ts` file. If you don't have a `src/middleware.ts` file yet, create one:
```typescript {filename:src/middleware.ts} {6}
-import { sentryBeforeResponseMiddleware } from '@sentry/solidstart';
-import { createMiddleware } from '@solidjs/start/middleware';
+import { sentryBeforeResponseMiddleware } from "@sentry/solidstart";
+import { createMiddleware } from "@solidjs/start/middleware";
export default createMiddleware({
onBeforeResponse: [
@@ -115,13 +114,13 @@ export default createMiddleware({
And specify `src/middleware.ts` in `app.config.ts`:
```typescript {filename:app.config.ts} {7}
-import { withSentry } from '@sentry/solidstart';
-import { defineConfig } from '@solidjs/start/config';
+import { withSentry } from "@sentry/solidstart";
+import { defineConfig } from "@solidjs/start/config";
export default defineConfig(
withSentry({
// other SolidStart config options...
- middleware: './src/middleware.ts',
+ middleware: "./src/middleware.ts",
})
);
```
@@ -132,9 +131,9 @@ This creates a higher order component, which will enable Sentry to collect navig
```tsx {filename:app.tsx} {5,9,11}
import { Router } from "@solidjs/router";
import { FileRoutes } from "@solidjs/start/router";
-import { withSentryRouterRouting } from '@sentry/solidstart/solidrouter'
+import { withSentryRouterRouting } from "@sentry/solidstart/solidrouter";
-const SentryRouter = withSentryRouterRouting(Router)
+const SentryRouter = withSentryRouterRouting(Router);
export default function App() {
return (
@@ -161,18 +160,18 @@ For example, update your scripts in `package.json`.
```
- If you experience any issues during the server-side setup, read through the different installation methods
- or check out Troubleshooting.
+ If you experience any issues during the server-side setup, read through the
+ different installation methods
+ or check out{" "}
+ Troubleshooting.
## Add Readable Stack Traces to Errors
-To upload source maps, configure an auth token. Auth tokens can be passed to `withSentry` explicitly with the `authToken`
-option. You can also use the `SENTRY_AUTH_TOKEN` environment variable or have an `.env.sentry-build-plugin` file in the
+To upload source maps, you need to pass an auth token to `withSentry` explicitly with the `authToken`
+option. We highly recommend to store this token in an environment variable for security. You can also use the `SENTRY_AUTH_TOKEN` environment variable or have an `.env.sentry-build-plugin` file in the
working directory when building your project.
-
-
Update your `app.config.ts`:
```TypeScript {filename:app.config.ts}
@@ -187,12 +186,21 @@ export default defineConfig(
{
org: "___ORG_SLUG___",
project: "___PROJECT_SLUG___",
- authToken: "___ORG_AUTH_TOKEN___",
+ // store your auth token in an environment variable
+ authToken: process.env.SENTRY_AUTH_TOKEN,
}
),
);
```
+Store your token in an environment variable:
+
+
+
+```bash {filename:.env}
+SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___
+```
+
or create a `.env.sentry-build-plugin` file:
```bash {filename:.env.sentry-build-plugin}