Vercel AI
Adds instrumentation for Vercel AI SDK.
Import name: Sentry.vercelAIIntegration
The vercelAIIntegration adds instrumentation for the ai SDK by Vercel to capture spans using the AI SDK's built-in telemetry.
Don't use the AI SDK's registerTelemetry API (AI SDK v7 and above) together with this integration. vercelAIIntegration already instruments the AI SDK, so registering telemetry separately produces duplicate spans.
The integration is enabled by default and captures spans for all ai function calls. No setup code is needed beyond enabling tracing:
Sentry.init({
dsn: "___PUBLIC_DSN___",
tracesSampleRate: 1.0,
});
Sentry.init({
dsn: "___PUBLIC_DSN___",
tracesSampleRate: 1.0,
});
Prompts and completions are not captured until you opt in. See Record inputs and outputs.
Prompts and completions are not captured by default, because they usually contain user data. Turn recording on with recordInputs and recordOutputs.
Sentry resolves both settings in this order, and stops at the first one that is set:
- The integration option — applies to every call.
- The call's
experimental_telemetry— applies to that call. dataCollection.genAI— applies to every call.
The integration option wins over the call, not the other way around. If you set recordInputs: false on the integration, no call site can turn it back on.
Set the options on the integration to cover every call. Re-adding the integration replaces the default instance and configures it:
Sentry.init({
dsn: "___PUBLIC_DSN___",
tracesSampleRate: 1.0,
integrations: [
Sentry.vercelAIIntegration({
recordInputs: true,
recordOutputs: true,
}),
],
});
Sentry.init({
dsn: "___PUBLIC_DSN___",
tracesSampleRate: 1.0,
integrations: [
Sentry.vercelAIIntegration({
recordInputs: true,
recordOutputs: true,
}),
],
});
To record only some calls, leave the integration options unset and set them per call instead:
const result = await generateText({
model: openai("gpt-4o"),
experimental_telemetry: {
recordInputs: true,
recordOutputs: true,
},
});
const result = await generateText({
model: openai("gpt-4o"),
experimental_telemetry: {
recordInputs: true,
recordOutputs: true,
},
});
dataCollection: {} also turns recording on, but it opts you into the SDK's permissive defaults for every other category too: user identity, cookies, headers, HTTP bodies, query parameters, and stack-frame locals. Prefer the integration and per-call options above unless you want all of it. See dataCollection.
Every instrumented ai function takes an experimental_telemetry object. Use it to control one call instead of all of them. For the full list of fields, see the AI SDK telemetry metadata docs.
To capture no span for one call, set isEnabled to false:
const result = await generateText({
model: openai("gpt-4o"),
experimental_telemetry: { isEnabled: false },
});
const result = await generateText({
model: openai("gpt-4o"),
experimental_telemetry: { isEnabled: false },
});
Spans carry the AI SDK function name, not yours, so a trace with several generateText calls is hard to read. Set functionId to label the call site. It appears on the span as gen_ai.function_id:
const result = await generateText({
model: openai("gpt-4o"),
experimental_telemetry: {
functionId: "summarize-ticket",
},
});
const result = await generateText({
model: openai("gpt-4o"),
experimental_telemetry: {
functionId: "summarize-ticket",
},
});
The integration captures spans for the ToolLoopAgent class. Each call to generate() or stream() creates an agent span, with the individual LLM requests and tool executions as child spans.
ToolLoopAgent takes its telemetry settings on the constructor, not on generate() or stream():
const agent = new ToolLoopAgent({
model: openai("gpt-4o"),
tools: {
/* ... */
},
experimental_telemetry: {
functionId: "weather-agent",
},
});
const result = await agent.generate({
prompt: "What is the weather in San Francisco?",
});
const agent = new ToolLoopAgent({
model: openai("gpt-4o"),
tools: {
/* ... */
},
experimental_telemetry: {
functionId: "weather-agent",
},
});
const result = await agent.generate({
prompt: "What is the weather in San Francisco?",
});
Spans are captured without the experimental_telemetry block. Pass it only to set functionId or the recording options.
Type: boolean
Truncates recorded input messages so large payloads stay within span size limits. Affects inputs only, not outputs.
Defaults to true.
Sentry.init({
integrations: [Sentry.vercelAIIntegration({ enableTruncation: false })],
});
Sentry.init({
integrations: [Sentry.vercelAIIntegration({ enableTruncation: false })],
});
Type: boolean
Registers the integration's span processors even when the ai module can't be detected. Set this when your build bundles ai, which defeats module detection. See Troubleshooting.
Defaults to false.
Sentry.init({
integrations: [Sentry.vercelAIIntegration({ force: true })],
});
Sentry.init({
integrations: [Sentry.vercelAIIntegration({ force: true })],
});
Type: boolean
Records inputs to the ai function call. See Record inputs and outputs for the full resolution order and the per-call alternative.
Type: boolean
Records outputs from the ai function call. See Record inputs and outputs for the full resolution order and the per-call alternative.
Spans are captured for these ai functions:
generateText()streamText()generateObject()streamObject()embed()embedMany()rerank()
Plus generate() and stream() on ToolLoopAgent.
ai:>=3.0.0 <=7
- Sentry SDK:
10.6.0+
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").