---
title: "Manual Setup"
description: "Learn how to manually set up Sentry in your Remix app and capture your first errors."
url: https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup/
---

# Manual Setup | Sentry for Remix

For the fastest setup, we recommend using the [wizard installer](https://docs.sentry.io/platforms/javascript/guides/remix.md).

## [Prerequisites](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#prerequisites)

You need:

* A Sentry [account](https://sentry.io/signup/) and [project](https://docs.sentry.io/product/projects.md)
* Your application up and running
* Remix version `2.0.0`+

## [Step 1: Install](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#step-1-install)

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

Error Monitoring\[ ]Tracing\[ ]Profiling\[ ]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.
* [**Profiling**](https://docs.sentry.io/product/explore/profiling.md):
  <!-- -->
  Gain deeper insight than traditional tracing without custom instrumentation, letting you discover slow-to-execute or resource-intensive functions in your app.
* [**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/remix/manual-setup.md#install-the-sentry-sdk)

Run the command for your preferred package manager to add the Sentry SDK to your application:

```bash
npm install @sentry/remix --save
```

```bash
npm install @sentry/remix @sentry/profiling-node --save
```

## [Step 2: Configure](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#step-2-configure)

### [Configure Client-Side Sentry](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#configure-client-side-sentry)

Create a client file `entry.client.tsx` in the `app` folder of your project if you don't have one already. In this file, import and initialize the Sentry SDK:

`entry.client.tsx`

```typescript
import { useLocation, useMatches } from "@remix-run/react";
import * as Sentry from "@sentry/remix";
import { useEffect } from "react";

Sentry.init({
  dsn: "___PUBLIC_DSN___",

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

  integrations: [
    // ___PRODUCT_OPTION_START___ performance
    Sentry.browserTracingIntegration({
      useEffect,
      useLocation,
      useMatches,
    }),
    // ___PRODUCT_OPTION_END___ performance
    // ___PRODUCT_OPTION_START___ session-replay
    // Replay is only available in the client
    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___ 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/configuration/options/#traces-sample-rate
  tracesSampleRate: 1.0,

  // Set `tracePropagationTargets` to control for which URLs distributed tracing should be enabled
  tracePropagationTargets: ["localhost", /^https:\/\/yourserver\.io\/api/],
  // ___PRODUCT_OPTION_END___ performance
  // ___PRODUCT_OPTION_START___ session-replay

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

  // Enable logs to be sent to Sentry
  enableLogs: true,
  // ___PRODUCT_OPTION_END___ logs
});
```

#### [Remix ErrorBoundary](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#remix-errorboundary)

To capture errors from your [ErrorBoundary](https://remix.run/docs/en/main/route/error-boundary), define it in `root.tsx` to act as a fallback for all routes or create route-specific error boundaries in your route components.

In your `ErrorBoundary` component, use `Sentry.captureRemixErrorBoundaryError` to send the captured error to Sentry:

`root.tsx`

```tsx
import { captureRemixErrorBoundaryError } from "@sentry/remix";

export const ErrorBoundary = () => {
  const error = useRouteError();

  captureRemixErrorBoundaryError(error);

  return <div> ... </div>;
};
```

#### [Performance Monitoring](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#performance-monitoring)

Wrap your Remix root component with `withSentry` to capture performance data:

`root.tsx`

```tsx
import {
  Links,
  LiveReload,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from "@remix-run/react";

import { withSentry } from "@sentry/remix";

function App() {
  return (
    <html>
      <head>
        <Meta />
        <Links />
      </head>
      <body>
        <Outlet />
        <ScrollRestoration />
        <Scripts />
        <LiveReload />
      </body>
    </html>
  );
}

export default withSentry(App);
```

### [Configure Server-Side Sentry](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#configure-server-side-sentry)

Create an instrumentation file `instrument.server.mjs` in your project's root folder and initialize the Sentry SDK within it:

`instrument.server.mjs`

```typescript
import * as Sentry from "@sentry/remix";
// ___PRODUCT_OPTION_START___ profiling
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: and captures action formData attributes
  // https://docs.sentry.io/platforms/javascript/guides/remix/configuration/options/#sendDefaultPii
  sendDefaultPii: true,
  // ___PRODUCT_OPTION_START___ profiling

  // Add our Profiling integration
  integrations: [nodeProfilingIntegration()],
  // ___PRODUCT_OPTION_END___ profiling
  // ___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/configuration/options/#traces-sample-rate
  tracesSampleRate: 1.0,
  // ___PRODUCT_OPTION_END___ performance
  // ___PRODUCT_OPTION_START___ profiling

  // Enable profiling for a percentage of sessions
  // Learn more at
  // https://docs.sentry.io/platforms/javascript/configuration/options/#profileSessionSampleRate
  profileSessionSampleRate: 1.0,
  // ___PRODUCT_OPTION_END___ profiling
  // ___PRODUCT_OPTION_START___ logs

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

  // Optionally capture action formData attributes with errors.
  // This requires `sendDefaultPii` set to true as well.
  captureActionFormDataKeys: {
    key_x: true,
    key_y: true,
  },
});
```

Then run your Remix server using the `--import` command line option and point it to this file to make sure the Sentry module loads before any other application code runs:

```bash
NODE_OPTIONS='--import=./instrument.server.mjs' remix-serve build
# or
NODE_OPTIONS='--require=./instrument.server.cjs' remix-serve build
```

Are you using Express?

If you use the Express server instead of the built-in Remix server, you can import your instrumentation file directly at the top of your server implementation.

`server.(mjs|cjs)`

```typescript
// import the Sentry instrumentation file before anything else.
import "./instrument.server.mjs";
// alternatively `require('./instrument.server.cjs')`

// ...

const app = express();

// ...
```

### [Capture Server-Side Errors](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#capture-server-side-errors)

To automatically capture server-side errors, instrument the [`handleError`](https://remix.run/docs/en/main/file-conventions/entry.server#handleerror) function in your server entry point (`entry.server.tsx`). You can wrap your custom error handler with `wrapHandleErrorWithSentry` or directly use `sentryHandleError`:

`entry.server.tsx`

```typescript
import * as Sentry from "@sentry/remix";

export const handleError = Sentry.wrapHandleErrorWithSentry(
  (error, { request }) => {
    // Custom handleError implementation
  },
);

// Alternative: Use the Sentry utility function if you don't need to wrap a custom function
export const handleError = Sentry.sentryHandleError;
```

##### Tip

Sentry's Remix SDK automatically records your [`action`](https://remix.run/docs/en/main/route/action) and [`loader`](https://remix.run/docs/en/main/route/loader) transactions for performance monitoring. You can also initialize Sentry's database integrations, such as [Prisma](https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/prisma.md), to get spans for your database calls.

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

To upload source maps for clear error stack traces, add your Sentry auth token, organization, and project slug in your `vite.config.ts` file:

##### Not using Vite?

Check our [Source Maps documentation](https://docs.sentry.io/platforms/javascript/guides/remix/sourcemaps.md) for alternative setup options.

`vite.config.ts`

```javascript
import { defineConfig } from "vite";
import { vitePlugin as remix } from "@remix-run/dev";

import { sentryVitePlugin } from "@sentry/vite-plugin";


export default defineConfig({
  plugins: [
    remix({
      // ... your Remix plugin options
    }),

    sentryVitePlugin({
      // If you use .sentryclirc or environment variables,
      // you don't need to specify these options
      org: "___ORG_SLUG___",
      project: "___PROJECT_SLUG___",
      // store your auth token in an environment variable
      authToken: process.env.SENTRY_AUTH_TOKEN,
    }),

  ],


  build: {
    sourcemap: "hidden",
    // ... rest of your Vite build options
  },

});
```

To keep your auth token secure, always store it in an environment variable instead of directly in your files:

`.env`

```bash
SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___
```

Using environment variables in Vite configs

Vite doesn't automatically load `.env` files into `process.env` when evaluating the config file. If you store your auth token in a `.env` file and want to access it via `process.env.SENTRY_AUTH_TOKEN`, use Vite's [`loadEnv`](https://vite.dev/guide/api-javascript#loadenv) helper:

`vite.config.js`

```javascript
import { defineConfig, loadEnv } from "vite";

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), "");

  return {
    plugins: [
      sentryVitePlugin({
        authToken: env.SENTRY_AUTH_TOKEN,
        // ...
      }),
    ],
  };
});
```

Alternatively, use a `.env.sentry-build-plugin` file, which the Sentry plugin reads automatically.

## [Step 4: Avoid Ad Blockers With Tunneling (Optional)](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#step-4-avoid-ad-blockers-with-tunneling-optional)

You can prevent ad blockers from blocking Sentry events using tunneling. Use the `tunnel` option to add an API endpoint in your application that forwards Sentry events to Sentry servers.

To enable tunneling, update `Sentry.init` in your `entry.client.tsx` file with the following option:

`entry.client.tsx`

```javascript
Sentry.init({
  dsn: "___PUBLIC_DSN___",

  tunnel: "/tunnel",

});
```

This will send all events to the `tunnel` endpoint. However, the events need to be parsed and redirected to Sentry, so you'll need to do additional configuration on the server. You can find a detailed explanation on how to do this on our [Troubleshooting page](https://docs.sentry.io/platforms/javascript/guides/remix/troubleshooting.md#using-the-tunnel-option).

## [Step 5: Verify Your Setup](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#step-5-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/remix/manual-setup.md#issues)

To verify that Sentry captures errors and creates issues in your Sentry project, add a test button to one of your pages:

```javascript
<button
  type="button"
  onClick={() => {
    throw new Error("Sentry Example Frontend Error");
  }}
>
  <span>Throw Sample Error</span>
</button>;
```

Open the page in a browser and click the button to trigger a frontend error.

### [Tracing](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#tracing)

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

```javascript
<button
  type="button"
  onClick={async () => {
    await Sentry.startSpan(
      {
        name: "Example Frontend Span",
        op: "test",
      },
      async () => {
        const res = await fetch("/api/sentry-example-api");
        if (!res.ok) {
          throw new Error("Sentry Example Frontend Error");
        }
      },
    );
  }}
>
  <span>Throw Sample Error</span>
</button>;
```

Open the page in a browser (for most Remix applications, this will be at localhost:3000) and click the button to trigger the frontend error and a trace.

### [Logs NEW](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.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",
});
```

##### 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.

### [View Captured Data in Sentry](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.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
  <!-- -->
  [**Profiles**](https://sentry.io/orgredirect/organizations/:orgslug/profiling/)
  <!-- -->
  page, select a transaction, and then a profile ID to view its flame graph. For more information, click
  <!-- -->
  [here](https://docs.sentry.io/product/explore/profiling/profile-details.md).
* 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/remix/manual-setup.md#next-steps)

At this point, you should have integrated Sentry into your Remix application and should already be sending error and performance 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/remix/usage.md)
* Continue to [customize your configuration](https://docs.sentry.io/platforms/javascript/guides/remix/configuration.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?

* If you encountered issues with the manual setup, try [our installation wizard](https://docs.sentry.io/platforms/javascript/guides/remix.md)
* Find various topics in [Troubleshooting](https://docs.sentry.io/platforms/javascript/guides/remix/troubleshooting.md)
* [Get support](https://sentry.zendesk.com/hc/en-us/)
