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

**URL:** https://sentry.io/cookbook/vercel-ai-sdk-otel-sentry/

---

Keep your existing Vercel AI SDK and OpenTelemetry setup, and route LLM spans to Sentry's AI Agents Insights without ripping out @vercel/otel.

**Time:** 15–20 minutes | **Difficulty:** Intermediate

## What You'll Learn

- Configured Sentry to coexist with an existing @vercel/otel setup

- Registered Sentry's OpenTelemetry components as the span processor, sampler, and propagator

- Enabled Vercel AI SDK's experimental_telemetry on your LLM calls

- Viewed LLM spans in Sentry's AI Agents Insights

**Topics:** Tracing, AI Observability, Agent Tracing

**SDKs:** Next.js, JavaScript

## Before you start

**SDKs & packages**

- A project already using [Vercel AI SDK](https://ai-sdk.dev/) with [@vercel/otel](https://www.npmjs.com/package/@vercel/otel) instrumentation

- Node.js 18+

**Accounts & access**

- [Sentry account](https://sentry.io/signup/) with a project and DSN

**Knowledge**

- Basic familiarity with OpenTelemetry concepts (spans, processors, propagators)

- Familiarity with the Vercel AI SDK `generateText` / `streamText` APIs

## Steps

### 1. Install Sentry and OpenTelemetry packages

Add `@sentry/opentelemetry` alongside your runtime SDK. This package exposes the Sampler, Propagator, and SpanProcessor that bridge OTel spans into Sentry. Keep your existing `@vercel/otel` and `ai` packages. They don't change.

```bash
npm install @sentry/opentelemetry
```

[Sentry custom OpenTelemetry setup](https://docs.sentry.io/platforms/javascript/guides/nextjs/opentelemetry/custom-setup/)

### 2. Initialize Sentry with skipOpenTelemetrySetup

By default, the Sentry SDK registers its own OpenTelemetry SDK on startup. Because `@vercel/otel` is already doing that, you need to tell Sentry to skip it by setting `skipOpenTelemetrySetup: true`. This makes Sentry a span **consumer** rather than the owner of the OTel pipeline.

```javascript
Sentry.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 1.0,
  skipOpenTelemetrySetup: true,
});
// Continue to Step 3 to register @vercel/otel
```

[skipOpenTelemetrySetup reference](https://docs.sentry.io/platforms/javascript/guides/nextjs/opentelemetry/custom-setup/)

### 3. Register @vercel/otel with Sentry's OTel components

Plug Sentry's `SentryPropagator`, `SentrySampler`, and `SentrySpanProcessor` into `registerOTel`. The `"auto"` entries preserve Vercel's defaults so your existing instrumentation keeps working. You're **adding** Sentry to the pipeline, not replacing anything. If you're using Next.js, [here's how to do it](https://docs.sentry.io/platforms/javascript/guides/nextjs/opentelemetry/custom-setup/).

```typescript
import { registerOTel } from "@vercel/otel";
import {
  SentryPropagator,
  SentrySampler,
  SentrySpanProcessor,
} from "@sentry/opentelemetry";
import * as Sentry from "@sentry/node";

const client = Sentry.getClient();

if (client) {
  registerOTel({
    serviceName: "vercel-ai-otel-sentry-demo",
    contextManager: new Sentry.SentryContextManager(),
    propagators: ["auto", new SentryPropagator()],
    traceSampler: new SentrySampler(client),
    spanProcessors: ["auto", new SentrySpanProcessor()],
  });
}
```

[Wiring Sentry into an existing OTel pipeline](https://docs.sentry.io/platforms/javascript/guides/nextjs/opentelemetry/custom-setup/)

### 4. Enable experimental_telemetry on your LLM calls

The Vercel AI SDK only emits telemetry when you opt in. Add `experimental_telemetry` to every LLM call with `isEnabled: true` and a stable `functionId` so Sentry can group related runs together. `recordInputs` and `recordOutputs` attach the prompt and completion to the trace, which is useful while debugging. Turn them off if your prompts can contain sensitive data.

```javascript
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";

const MODEL = "gpt-4o-mini";
const FUNCTION_ID = "summarize-article";

const { text } = await generateText({
  model: openai(MODEL),
  prompt,
  experimental_telemetry: {
    isEnabled: true,
    functionId: FUNCTION_ID,
    recordInputs: true,
    recordOutputs: true,
  },
});
```

[Vercel AI SDK telemetry docs](https://ai-sdk.dev/docs/ai-sdk-core/telemetry)

### 5. Verify your AI spans in Sentry

Run your app and trigger an LLM call. Within a minute, open [AI Agents Dashboard](https://sentry.io/orgredirect/organizations/:orgslug/dashboards/?filter=onlyPrebuilt&query=agents&sort=mostPopular) in Sentry. You'll see each `generateText` invocation as a trace, broken down by model, token counts, latency, and (if you enabled it) the full prompt and completion. Click into a trace to see the span waterfall. The Vercel AI SDK span sits alongside the surrounding HTTP, database, and custom spans from your app.

[AI Agents Dashboard documentation](https://docs.sentry.io/product/agents/dashboards/)

## Summary

**Your LLM calls are in Sentry.**

Your OpenTelemetry pipeline is unchanged, Vercel AI SDK keeps emitting standard spans, and Sentry is now your observability backend for every model invocation.

## Pro Tips

- Use a distinct `functionId` per logical AI task (`summarize-article`, `classify-support-ticket`) so the AI Agents view groups related runs and makes regressions obvious.

- Set a meaningful `serviceName` in `registerOTel`. Sentry uses it to group spans across services in the Trace Explorer, which matters the moment you have more than one worker.

- Keep `tracesSampleRate: 1.0` while you're bringing this up so you don't miss the first few spans to debugging. Dial it down once you trust the pipeline.

- Attach request-scoped context via `experimental_telemetry.metadata` (user ID, tenant, feature flag) so you can filter traces by those attributes in Sentry.

## Common Pitfalls

- Forgetting `skipOpenTelemetrySetup: true` causes two OpenTelemetry SDKs to register. You'll see duplicate spans, or worse, the Sentry SDK's setup silently winning and your `@vercel/otel` instrumentation disappearing.

- Omitting `"auto"` from `propagators` or `spanProcessors` strips out Vercel's defaults. You'll lose automatic HTTP, `fetch`, and Next.js span instrumentation without realizing it.

- Leaving `recordInputs: true` on in production can send user PII or secrets to Sentry as span attributes. Gate this behind an environment flag or turn it off for regulated data.

- In Next.js, importing `@vercel/otel` at the top of `instrumentation.ts` (instead of inside `register()` after `Sentry.init`) can load OTel before Sentry is ready. Keep the imports dynamic.

## FAQ

**Do I have to migrate off @vercel/otel to use Sentry?**

No. `@vercel/otel` remains the owner of the OpenTelemetry pipeline, and Sentry plugs in as an additional span processor, sampler, and propagator. Your existing instrumentation keeps working unchanged.

**What happens if I forget skipOpenTelemetrySetup?**

Both the Sentry SDK and `@vercel/otel` try to register OpenTelemetry globally. Depending on load order, you'll get either duplicate spans or, more commonly, your `@vercel/otel` config silently overridden. Always set `skipOpenTelemetrySetup: true` when combining the two.

**Does this only work with Next.js?**

No. `@vercel/otel` and `@sentry/opentelemetry` work in any Node.js runtime. The `registerOTel` call is identical whether you're running Next.js, a standalone Node server, a worker, or a serverless function. Next.js just happens to have a built-in `instrumentation.ts` entry point that makes the wiring convenient.

**Which Sentry SDK should I use?**

Use the SDK that matches your runtime: `@sentry/nextjs` for Next.js apps, `@sentry/node` for plain Node services, `@sentry/bun`, `@sentry/aws-serverless`, and so on. All of them accept `skipOpenTelemetrySetup` and expose the same `SentryPropagator` / `SentrySampler` / `SentrySpanProcessor` from `@sentry/opentelemetry`.

**Will Sentry see my existing non-AI OpenTelemetry spans too?**

Yes. Because `SentrySpanProcessor` is attached alongside Vercel's `"auto"` processors, every span your OTel pipeline produces (HTTP, `fetch`, database, custom) flows into Sentry as part of the same trace.

**Does recording inputs and outputs have a cost?**

It adds bytes to each span, which counts toward your Sentry transaction quota. For most apps the overhead is negligible, but if you're making high-volume calls with long prompts, consider sampling or disabling `recordInputs` / `recordOutputs` in production.

## Next Steps

- [solution/ai-observability](https://sentry.io/solutions/ai-observability/)

- [product/tracing](https://sentry.io/product/tracing/)

- [Monitor AI agent costs in Next.js](/cookbook/monitor-ai-agent-costs-nextjs/): A companion recipe that focuses on token-level cost tracking for Vercel AI SDK apps running in Sentry.

- [Add error monitoring on top](https://docs.sentry.io/platforms/javascript/guides/nextjs/): You already have Sentry installed. Make sure unhandled errors and API failures are captured with the same SDK.

---

*Source: [sentry.io/cookbook/vercel-ai-sdk-otel-sentry/](https://sentry.io/cookbook/vercel-ai-sdk-otel-sentry/)*
