# OpenTelemetry observability and distributed tracing

> Send OpenTelemetry traces and logs to Sentry for distributed tracing, error context, and code-level debugging. Direct OTLP ingestion, no collector required

**URL:** https://sentry.io/solutions/opentelemetry/

---

OpenTelemetry gives you a standard way to instrument your code. Sentry gives that telemetry data meaning: errors connected to traces, logs tied to issues, and debugging tools that point to the root cause in your code.

Send traces and logs directly via OTLP, forward them through the OTel Collector, or run Sentry SDKs alongside your existing OpenTelemetry setup.

## Details

### Send OTel data directly to Sentry

#### Point your OTLP exporter at Sentry and start seeing data

Configure your OpenTelemetry SDK to export traces and logs to Sentry's OTLP endpoint. Set the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable, add your auth header, and you're done. No Collector, no sidecar agents, no extra infrastructure to manage.

Standard OTel environment variables, nothing proprietary

Supports gzip compression and protobuf encoding

Works with any language that has an OpenTelemetry SDK

### Connect errors to the traces that caused them

#### The context that trace-only backends miss

Most OpenTelemetry backends show you traces and logs. Sentry connects those to the errors, stack traces, and breadcrumbs that explain what actually went wrong. When a Sentry SDK and OTel instrumentation run in the same service, they share the same trace ID automatically, so errors link to the exact span where they happened.

Stack traces with source context, not just span names

Breadcrumbs show the sequence of events leading to each failure

Every issue links to the commit and release that introduced it

### Trace across Sentry SDKs and OTel services in one view

#### One trace from frontend to OTel-instrumented backend

Your frontend uses a Sentry SDK. Your backend uses OpenTelemetry. Sentry propagates W3C Trace Context headers so both sides of the request show up in a single distributed trace, with timing for every span. You can follow a slow page load from the browser through your API, into the database query that caused it.

Unified traces across Sentry SDK and OTel-instrumented services

W3C Trace Context propagation works out of the box

Supported on 20+ frontend and mobile frameworks

### Forward infrastructure telemetry through the OTel Collector

#### Collect from infrastructure sources without changing application code

Use the OpenTelemetry Collector, Vector, or Fluent Bit to forward logs and traces from infrastructure sources into Sentry. The Sentry Exporter for the OTel Collector handles multi-project routing and automatic project creation, so each service's telemetry lands in the right place.

Supported pipelines: OpenTelemetry Collector, Vector, Fluent Bit

Infrastructure sources: AWS CloudWatch, Kafka, Nginx, syslog, Windows Events

Managed platform drains for Vercel, Cloudflare, and Heroku

## Cookbook recipes

- **Route your existing OpenTelemetry traces to Sentry with Next.js**: Keep your vendor-neutral OpenTelemetry instrumentation and start seeing your Next.js traces in Sentry. No SDK migration required. — [Learn more](https://sentry.io/cookbook/route-opentelemetry-traces-to-sentry/)

- **Send Vercel AI SDK telemetry to Sentry via OpenTelemetry**: Keep your existing Vercel AI SDK and OpenTelemetry setup, and route LLM spans to Sentry's AI Agents Insights without ripping out @vercel/otel. — [Learn more](https://sentry.io/cookbook/vercel-ai-sdk-otel-sentry/)

## OpenTelemetry FAQ

**Do I need an OpenTelemetry Collector to send data to Sentry?**

No. You can send traces and logs directly from your OTel SDK to Sentry's OTLP endpoint using standard environment variables. The Collector is optional, and useful when you need preprocessing, sampling, or routing to multiple destinations. For most applications, direct OTLP export is the simplest path.

**Should I use a Sentry SDK, an OTel SDK, or both?**

It depends on your setup. If you want the full Sentry experience (error tracking, session replays, profiling, crons), use the Sentry SDK, which includes built-in OTel support. If you already have OTel instrumentation, you can send that data directly to Sentry via OTLP. You can also run both: the Sentry SDK and OTel SDK share the same trace ID automatically in Node.js, Python, and Ruby.

**What is OTLP?**

OTLP (OpenTelemetry Protocol) is the standard wire protocol for sending telemetry data between OpenTelemetry SDKs, Collectors, and backends. Sentry accepts OTLP for both traces and logs, so any OTel-instrumented service can send data to Sentry without a proprietary exporter. You configure it with the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable.

**Does Sentry have an OpenTelemetry Collector exporter?**

Yes. Sentry provides a dedicated exporter for the OpenTelemetry Collector that supports multi-project routing and automatic project creation. This is useful for forwarding infrastructure telemetry from sources like AWS CloudWatch, Kafka, Nginx, and syslog without modifying application code.

**What is the difference between OpenTelemetry and Prometheus?**

Prometheus is a metrics collection and alerting system. OpenTelemetry is a broader observability framework that covers traces, logs, and metrics. They solve different problems and can work together: you can use OpenTelemetry to instrument your code and export metrics to Prometheus, while sending traces and logs to Sentry for error tracking and distributed tracing.

**Which OpenTelemetry signals does Sentry support?**

Sentry currently supports OpenTelemetry traces and logs via OTLP. Metric ingestion via OTLP is not yet supported. Sentry SDKs provide their own metrics capabilities alongside OTel trace and log support.

**Does the same data appear 1:1 in my OTel backend as in Sentry?**

Yes. The goal is accurate conversion of OTel data into Sentry. If you notice something missing, reach out to support or [open an issue on GitHub](https://github.com/getsentry/sentry/issues) and the team will route it to the right place.

**Where can I try OpenTelemetry with Sentry?**

Check out the [Sentry OpenTelemetry demo repo on GitHub](https://github.com/getsentry/opentelemetry-demo). It's a fork of the official OpenTelemetry example with a suite of microservices already instrumented with both Sentry and OTel SDKs.

## Customer Story

> Getting started with Sentry and OpenTelemetry was fast and easy. We chose Sentry because we can understand why and where something is slow, fix it quickly, and get ahead of user complaints.

- **100+** SDKs with built-in OpenTelemetry support

- **150K+** organizations use Sentry in production

- **3** supported pipeline tools: OTel Collector, Vector, Fluent Bit

## OpenTelemetry resources

- [Send your existing OpenTelemetry traces to Sentry](https://blog.sentry.io/send-your-existing-opentelemetry-traces/): How to route your existing OTel traces into Sentry with direct OTLP ingestion or the OpenTelemetry Collector.

- [[Cookbook] Route OpenTelemetry traces to Sentry](https://sentry.io/cookbook/route-opentelemetry-traces-to-sentry/): Step-by-step recipe for routing OTel traces from your services into Sentry using the Collector or direct export.

- [Structured logging with OpenTelemetry](https://blog.sentry.io/structured-logging-opentelemetry/): Send structured logs from OTel-instrumented services into Sentry for correlated debugging.

## Comparison

### OpenTelemetry with traditional backends

Traces and logs in one system, errors in another, with no connection between them.

Requires a Collector, exporters, and often a sidecar agent for each service.

Dashboards show latency and throughput, not the line of code that caused the problem.

Getting started typically requires a sales call or a guided demo.

Pricing scales with data volume in ways that are hard to predict.

### OpenTelemetry with Sentry

Errors, traces, and logs connected in one workflow, with stack traces and breadcrumbs attached.

Direct OTLP ingestion: point your SDK at Sentry, no Collector required for basic setups.

Every trace links to the function, file, and commit that caused the issue.

Install the SDK, see data in minutes. No sales call needed.

Transparent, predictable pricing with a generous free tier.

## Quick Start

### Python

Install the Sentry Python SDK with pip

```bash
pip install sentry-sdk
```

Configuration should happen as early as possible in your application's lifecycle.

```python
import sentry_sdk

sentry_sdk.init(
  dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
  # Add data like request headers and IP for users, if applicable;
  # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info
  send_default_pii=True,
  # Set traces_sample_rate to 1.0 to capture 100%
  # of transactions for tracing.
  traces_sample_rate=1.0,
  #Enable logs to be sent to Sentry
  enable_logs=True,
  # To collect profiles for all profile sessions,
  # set profile_session_sample_rate to 1.0.
  profile_session_sample_rate=1.0,
  # Profiles will be automatically collected while
  # there is an active span.
  profile_lifecycle="trace",
)
```

### JavaScript

Install the Sentry JavaScript SDK with npm

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

Configuration should happen as early as possible in your application's lifecycle.

```javascript
import * as Sentry from "@sentry/browser";

Sentry.init({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  // Adds request headers and IP for users, for more info visit:
  // https://docs.sentry.io/platforms/javascript/configuration/options/#sendDefaultPii
  sendDefaultPii: true,
  // Set tracesSampleRate to 1.0 to capture 100%
  // of transactions for tracing.
  tracesSampleRate: 1.0,
  // Set tracePropagationTargets to control for which URLs trace propagation should be enabled
  tracePropagationTargets: ["localhost", /^https:\/\/yourserver\.io\/api/],
  // Enable logs to be sent to Sentry
  enableLogs: true,
  // Set profilesSampleRate to 1.0 to profile every transaction.
  // Since profilesSampleRate is relative to tracesSampleRate,
  // the final profiling rate can be computed as tracesSampleRate * profilesSampleRate
  // For example, a tracesSampleRate of 0.5 and profilesSampleRate of 0.5 would
  // result in 25% of transactions being profiled (0.5*0.5=0.25)
  profilesSampleRate: 1.0,
  integrations: [
    Sentry.browserTracingIntegration(),
    Sentry.browserProfilingIntegration(),
  ],
});
```

### React

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

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

To import and initialize Sentry, create a file in your project's root directory, for example, `instrument.js`, and add the following code:

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

Sentry.init({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  // Adds request headers and IP for users, for more info visit:
  // https://docs.sentry.io/platforms/javascript/guides/react/configuration/options/#sendDefaultPii
  sendDefaultPii: true,
  // Set tracesSampleRate to 1.0 to capture 100%
  // of transactions for tracing.
  // Learn more at
  // https://docs.sentry.io/platforms/javascript/configuration/options/#traces-sample-rate
  tracesSampleRate: 1.0,
  // Set `tracePropagationTargets` to control for which URLs trace propagation should be enabled
  tracePropagationTargets: [/^//, /^https://yourserver.io/api/],
  // Enable logs to be sent to Sentry
  enableLogs: true,
  // Set profilesSampleRate to 1.0 to profile every transaction.
  // Since profilesSampleRate is relative to tracesSampleRate,
  // the final profiling rate can be computed as tracesSampleRate * profilesSampleRate
  // For example, a tracesSampleRate of 0.5 and profilesSampleRate of 0.5 would
  // result in 25% of transactions being profiled (0.5*0.5=0.25)
  profilesSampleRate: 1.0,
  integrations: [
    // If you're using react router, use the integration for your react router version instead.
    // Learn more at
    // https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/
    Sentry.browserTracingIntegration(),
    Sentry.browserProfilingIntegration(),
  ],
});
```

Initialize Sentry as early as possible in your application. We recommend putting the import of your initialization code as the first import in your app's entry point:

```javascript
// Sentry initialization should be imported first!
import "./instrument";
import App from "./App";
import { createRoot } from "react-dom/client";

const container = document.getElementById("app");
const root = createRoot(container);
root.render(<App />);
```

To make sure Sentry captures all your app's errors, configure error handling based on your React version. 
 For React versions 19 and up:  

```javascript
import { createRoot } from "react-dom/client";
import * as Sentry from '@sentry/react';

const container = document.getElementById("app");
const root = createRoot(container, {
  // Callback called when an error is thrown and not caught by an ErrorBoundary.
  onUncaughtError: Sentry.reactErrorHandler((error, errorInfo) => {
    console.warn('Uncaught error', error, errorInfo.componentStack);
  }),
  // Callback called when React catches an error in an ErrorBoundary.
  onCaughtError: Sentry.reactErrorHandler(),
  // Callback called when React automatically recovers from errors.
  onRecoverableError: Sentry.reactErrorHandler(),
});
root.render();
```

For React versions 18 and below, use the ErrorBoundary component to automatically send errors from specific component trees to Sentry and provide a fallback UI:

```javascript
import React from "react";
import * as Sentry from "@sentry/react";

<Sentry.ErrorBoundary fallback={<p>An error has occurred</p>}>
  <Example />
</Sentry.ErrorBoundary>;
```

### Next.js

To install Sentry using the installation wizard, run thrun the following command and step through the prompts:

```bash
npx @sentry/wizard@latest -i nextjs
```

For manual installation run the following command and use the following configurations:

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

Extend your app's default Next.js options by adding code with `withSentryConfig` into your `next.config.(js|mjs)` file:

```javascript
const { withSentryConfig } = require("@sentry/nextjs");
const nextConfig = {
  // Your existing Next.js configuration
};
// Make sure adding Sentry options is the last code to run before exporting
module.exports = withSentryConfig(nextConfig, {
  org: "example-org",
  project: "example-project",
  // Only print logs for uploading source maps in CI
  // Set to `true` to suppress logs
  silent: !process.env.CI,
  // Automatically tree-shake Sentry logger statements to reduce bundle size
  disableLogger: true,
});
```

#### Client-Side Configuration

```javascript
import * as Sentry from "@sentry/nextjs";
Sentry.init({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  // Adds request headers and IP for users, for more info visit:
  // https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii
  sendDefaultPii: true,
  // 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,
  // Enable logs to be sent to Sentry
  enableLogs: true,
  // Set profilesSampleRate to 1.0 to profile every transaction.
  // Since profilesSampleRate is relative to tracesSampleRate,
  // the final profiling rate can be computed as tracesSampleRate * profilesSampleRate
  // For example, a tracesSampleRate of 0.5 and profilesSampleRate of 0.5 would
  // result in 25% of transactions being profiled (0.5*0.5=0.25)
  profilesSampleRate: 1.0,
});

// This export will instrument router navigations, and is only relevant if you enable tracing.
// `captureRouterTransitionStart` is available from SDK version 9.12.0 onwards
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;
```

#### Server-Side Configuration

```javascript
import * as Sentry from "@sentry/nextjs";
Sentry.init({
  dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  // Adds request headers and IP for users, for more info visit:
  // https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#sendDefaultPii
  sendDefaultPii: true,
  // 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,
  // Enable logs to be sent to Sentry
  enableLogs: true,
});
```

#### Register Sentry Server-Side SDK Initialization

Create a Next.js Instrumentation file named `instrumentation.(js|ts)` in your project root or inside the `src` folder if you have one. Import your server and edge configurations, making sure that the imports point to your specific files:

```javascript
export async function register() {
  if (process.env.NEXT_RUNTIME === "nodejs") {
    await import("./sentry.server.config");
  }
  if (process.env.NEXT_RUNTIME === "edge") {
    await import("./sentry.edge.config");
  }
}
```

### Go

Grab the Sentry Go SDK:

```bash
go get "github.com/getsentry/sentry-go"
```

Configuration should happen as early as possible in your application's lifecycle.

```text
err := sentry.Init(sentry.ClientOptions{
  Dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  // Enable printing of SDK debug messages.
  // Useful when getting started or trying to figure something out.
  Debug: true,
  // Adds request headers and IP for users,
  // visit: https://docs.sentry.io/platforms/go/data-management/data-collected/ for more info
  SendDefaultPII: true,
  EnableTracing: true,
  // Set TracesSampleRate to 1.0 to capture 100%
  // of transactions for tracing.
  TracesSampleRate: 1.0,
})
if err != nil {
  log.Fatalf("sentry.Init: %s", err)
}
// Flush buffered events before the program terminates.
// Set the timeout to the maximum duration the program can afford to wait.
defer sentry.Flush(2 * time.Second)
```

### Ruby

Add the sentry-ruby gem to your Gemfile:

```ruby
gem "sentry-ruby"
```

Configuration should happen as early as possible in your application's lifecycle.

```ruby
require 'sentry-ruby'

Sentry.init do |config|
  config.dsn = 'https://examplePublicKey@o0.ingest.sentry.io/0'

  # get breadcrumbs from logs
  config.breadcrumbs_logger = [:sentry_logger, :http_logger]

  # Add data like request headers and IP for users, if applicable;
  # see https://docs.sentry.io/platforms/ruby/data-management/data-collected/ for more info
  config.send_default_pii = true
  # enable tracing
  # we recommend adjusting this value in production
  config.traces_sample_rate = 1.0
  # Enable logs to be sent to Sentry
  config.enable_logs = true
  # enable profiling
  # this is relative to traces_sample_rate
  config.profiles_sample_rate = 1.0
end
```

### PHP

Install the Sentry SDK using Composer:

```bash
composer require sentry/sentry
```

To use Profiling, you'll also need to install the Excimer extension via PECL:

```bash
pecl install excimer
```

To capture all errors, even the one during the startup of your application, you should initialize the Sentry PHP SDK as soon as possible.

```php
\Sentry\init([
  'dsn' => 'https://examplePublicKey@o0.ingest.sentry.io/0',
  // Add request headers, cookies and IP address,
  // see https://docs.sentry.io/platforms/php/data-management/data-collected/ for more info
  'send_default_pii' => true,
  // Specify a fixed sample rate
  'traces_sample_rate' => 1.0,
  // Enable logs to be sent to Sentry
  'enable_logs' => true,
  // Set a sampling rate for profiling - this is relative to traces_sample_rate
  'profiles_sample_rate' => 1.0,
]);
```

### .NET

Install the NuGet package to add the Sentry dependency:

```shell
dotnet add package Sentry -v 5.16.2
```

To use Profiling, you'll also need to install the Sentry.Profiling package:

```shell
dotnet add package Sentry.Profiling -v 5.16.2
```

To capture all errors, even the one during the startup of your application, you should initialize the Sentry .NET SDK as soon as possible.

```csharp
SentrySdk.Init(options =>
{
    options.Dsn = "https://examplePublicKey@o0.ingest.sentry.io/0";
    options.Debug = true;
    // Adds request URL and headers, IP and name for users, etc.
    options.SendDefaultPii = true;
    // A fixed sample rate of 1.0 - 100% of all transactions are getting sent
    options.TracesSampleRate = 1.0f;
    // A sample rate for profiling - this is relative to TracesSampleRate
    options.ProfilesSampleRate = 1.0f;
});
```

---

*Source: [sentry.io/solutions/opentelemetry/](https://sentry.io/solutions/opentelemetry/)*
