---
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`+

## [Install](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#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
```

## [Configure](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#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`:

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

`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;
```

### [Add Readable Stack Traces With Source Maps (Optional)](https://docs.sentry.io/platforms/javascript/guides/remix/manual-setup.md#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.

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

`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,
        // ...
      }),
    ],
  };
});
```

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

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

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

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

  tunnel: "/tunnel",

});
```

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

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

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

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

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

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

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

```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>;
```

### [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",
});
```

### [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/)
