Automatic Instrumentation

The Sentry SDK provides a BrowserTracing integration to add automatic instrumentation for monitoring the performance of browser applications.

The BrowserTracing integration creates a new transaction for each page load and navigation event, and creates a child span for every XMLHttpRequest or fetch request that occurs while those transactions are open.

To enable tracing, include the BrowserTracing integration in your SDK configuration options.

To use react-router integration, import and set a custom routing instrumentation using a custom history. Make sure you use a Router component combined with createBrowserHistory (or equivalent).

Copied
import { Router } from "react-router-dom";
import { createBrowserHistory } from "history";

import * as Sentry from "@sentry/react";

const history = createBrowserHistory();

Sentry.init({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",

  integrations: [
    Sentry.reactRouterV5BrowserTracingInstrumentation({ history }),
      // You can also use one of:
      // * reactRouterV3BrowserTracingInstrumentation
      // * reactRouterV4BrowserTracingInstrumentation
      // * reactRouterV6BrowserTracingInstrumentation
      // or just browserTracingIntegration
    }),
  ],

  // We recommend adjusting this value in production, or using tracesSampler
  // for finer control
  tracesSampleRate: 1.0,
});

Now you should be generating pageload/navigation transactions from the BrowserTracing integration, using Sentry's react-router instrumentation.

By default, the browserTracingIntegration() will create a pageload span for when the page is initially loaded, as well as a navigation span for whenever the URL changes afterwards.

To make sure that spans are created correctly for a custom routing setup, you'll need to opt out of the default span creation by setting instrumentNavigation: false and instrumentPageLoad: false in the browserTracingIntegration() options. You can then manually create spans like this:

Copied
Sentry.init({
  integrations: [
    Sentry.browserTracingIntegration({
      // disable automatic span creation
      instrumentNavigation: false,
      instrumentPageLoad: false,
    }),
  ],
});

// We start the pageload span as early as possible!
let pageLoadSpan = Sentry.startBrowserTracingPageLoadSpan({
  name: window.location.pathname,
  attributes: {
    [Sentry.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url",
  },
});

// Somewhere, instrument your router like this:
myRouter.on("routeChange", (route) => {
  const client = Sentry.getClient();

  // Make sure that the pageload span uses the route name
  // After that, each route change should trigger a navigation span (which will automatically finish the previous one)
  if (pageLoadSpan) {
    pageLoadSpan.updateName(route.name);
    pageLoadSpan.setAttribute(Sentry.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, "route");
    pageLoadSpan = undefined;
  } else {
    Sentry.startBrowserTracingNavigationSpan(client, {
      op: "navigation",
      name: route.name, // or what the name of the span should be
      attributes: {
        [Sentry.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "route",
      },
    });
  }
});

Supported options:

A list of strings and regular expressions. The JavaScript SDK will attach the sentry-trace and baggage headers to all outgoing XHR/fetch requests whose destination contains a string in the list or matches a regex in the list. If your frontend is making requests to a different domain, you'll need to add it there to propagate the sentry-trace and baggage headers to the backend services, which is required to link transactions together as part of a single trace.

The tracePropagationTargets option matches the entire request URL, not just the domain. Using stricter regex to match certain parts of the URL ensures that requests don't unnecessarily have additional headers attached.

The default value of tracePropagationTargets is ['localhost', /^\//]. This means that by default, tracing headers are only attached to requests that contain localhost in their URL or requests whose URL starts with a '/' (for example GET /api/v1/users).

For example:

  • A frontend application is served from example.com.
  • A backend service is served from api.example.com.
  • During development, the backend service is served from localhost.
  • The frontend application makes API calls to the backend.
  • Set the tracePropagationTargets option to ["localhost", /^https:\/\/api\.example\.com/].
  • Now outgoing XHR/fetch requests to your backend service will get the sentry-trace and baggage headers attached.
Copied
Sentry.init({
  // ...
  integrations: [Sentry.browserTracingIntegration()],

  // Set `tracePropagationTargets` to control for which URLs distributed tracing should be enabled
  tracePropagationTargets: ["localhost", /^https:\/\/yourserver\.io\/api/],
});

You will need to configure your web server CORS to allow the sentry-trace and baggage headers. The configuration might look like "Access-Control-Allow-Headers: sentry-trace" and "Access-Control-Allow-Headers: baggage", but it depends on your set up. If you do not allow the two headers, the request might be blocked.

beforeStartSpan is called at the start of every pageload or navigation span, and is passed an object containing data about the span which will be started. With beforeStartSpan you can modify that data or drop the transaction entirely by returning undefined.

One common use case is parameterizing transaction names. For both pageload and navigation transactions, the BrowserTracing integration uses the browser's window.location value to generate a transaction name. Using beforeStartSpan lets you modify the transaction name to make it more generic, so that, for example, transactions named GET /users/12312012 and GET /users/11212012 can both be renamed to GET /users/:userid. That way they'll be grouped together.

Copied
Sentry.init({
  // ...
  integrations: [
    Sentry.browserTracingIntegration({
      beforeStartSpan: (context) => {
        return {
          ...context,
          // You could use your UI's routing library to find the matching
          // route template here. We don't have one right now, so do some basic
          // parameter replacements.
          name: location.pathname
            .replace(/\/[a-f0-9]{32}/g, "/<hash>")
            .replace(/\/\d+/g, "/<digits>"),
        };
      },
    }),
  ],
});

This function can be used to filter out unwanted spans such as XHRs running health checks or something similar. If this function isn't specified, spans will be created for all requests.

Copied
Sentry.init({
  // ...
  integrations: [
    Sentry.browserTracingIntegration({
      shouldCreateSpanForRequest: (url) => {
        // Do not create spans for outgoing requests to a `/health/` endpoint
        return !url.match(/\/health\/?$/);
      },
    }),
  ],
});

The idle time, measured in ms, to wait until the transaction will be finished, if there are no unfinished spans. The transaction will use the end timestamp of the last finished span as the endtime for the transaction.

The default is 1000.

The maximum duration of the transaction, measured in ms. If the transaction duration hits the finalTimeout value, it will be finished.

The default is 30000.

The time, measured in ms, one heartbeat takes. If no new spans were started or no open spans finished within three heartbeats, the transaction will be finished. The heartbeat count restarts whenever a new span is created or an open span is finished.

The default is 5000.

This flag enables or disables creation of navigation transaction on history changes.

The default is true.

This flag enables or disables creation of pageload transaction on first pageload.

The default is true.

This option flags transactions when tabs are moved to the background with "cancelled". Because browser background tab timing is not suited for precise measurements of operations and can affect your statistics in nondeterministic ways, we recommend that this option be enabled.

The default is true.

This option determines whether spans for long tasks automatically get created.

The default is true.

This option determines whether interactions spans automatically get created when an Interaction to Next Paint (INP) event is detected. Interactions are scored and surfaced in the Web Vitals module.

The default is false.

Copied
Sentry.init({
  // ...
  integrations: [
    Sentry.browserTracingIntegration({
        enableInp: true,
    }),
  ],
});
Help improve this content
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").