@ai-sdk/otel). The simplest setup is @arizeai/phoenix-otel, which handles the OpenTelemetry provider, OpenInference span processing, and export to Phoenix in a single register() call.
Version compatibility
AI SDK v7 telemetry requires Node.js 22 or newer.
Installation
Setup
Since AI SDK v7, telemetry is emitted once you register a telemetry integration withregisterTelemetry(new OpenTelemetry(...)). Pair that with register() from @arizeai/phoenix-otel, which processes the resulting spans and exports them to Phoenix:
node --import ./instrumentation.ts index.ts, or import "./instrumentation.js" at the top of your application’s entrypoint.
Once the telemetry integration is registered, AI SDK calls are traced by default; no per-call configuration is required. Use the telemetry option for per-call metadata such as functionId, or to opt out with isEnabled: false.
ToolLoopAgent run is traced end to end, with the agent, each LLM step, and every tool call captured as spans in a single trace. See the AI SDK agent example for a complete runnable project.
register() uses a batch span processor by default, so spans still queued when a short-lived script exits may not be exported. Call await provider.shutdown() before exit to flush them, or pass batch: false to register() for immediate export.Decision models
AI SDK decision models, such as OpenAI’sgpt-6-luna through openai.decisionModel() or TypeSafe’s Jev through @ai-sdk/typesafe-ai, answer typed questions about a shared state instead of generating text. Calls made through the AI SDK’s experimental_decide are traced as DECISION spans rather than LLM spans, with no extra instrumentor. This requires @arizeai/openinference-vercel 3.3.0 or later, plus ai 7.0.128 and @ai-sdk/otel 1.0.128 or later. @arizeai/phoenix-otel 2.x depends on @arizeai/openinference-vercel with a caret range, so a fresh install resolves to 3.3.0 or later. In an existing project, check the version in your lockfile and run npm update @arizeai/openinference-vercel if it is older.
Two options on the OpenTelemetry integration shape what Phoenix receives:
experimental_decision: truerecords the decision state, questions, and answers. Without it the spans carry the model and token counts but no input or output.enrichSpan: enrichSpanWithOpenInferencetells the processor which of the two spans the AI SDK emits per call is the model call. The SDK emits an outer operation span and a child model-call span with identicalgen_ai.*attributes, so without this hint both are exported as DECISION spans.enrichSpanWithOpenInferenceis re-exported from the ESM-only@arizeai/phoenix-otel/vercelsubpath.
decide <model>, for example decide gpt-6-luna: a CHAIN span for the decide operation, carrying the state and questions as input and the answers as output, with a child DECISION span for the model call carrying:
decision.systemanddecision.provider, for exampleopenaiortypesafedecision.request.model_name,decision.response.model_name, anddecision.model_name. The response model needs@ai-sdk/otel1.0.138 or later; earlier versions do not record it on decide spans.decision.token_count.inputanddecision.token_count.output. The output count is often0, since the answers are typed values rather than generated tokens.
decision.* rather than llm.*, decision calls stay out of Phoenix’s LLM token and cost reporting.
TypeScript classification evaluators from
@arizeai/phoenix-evals take the same path when given a decision model. They enable experimental_decision on their own telemetry integration, so the state, questions, and answers are recorded with no further setup. They do not set enrichSpan, so the outer operation span is also exported as a DECISION span rather than a CHAIN span.Next.js
In a Next.js project, register the telemetry integration and@vercel/otel from the register() function in instrumentation.ts, using the OpenInference span processor from @arizeai/openinference-vercel, the same processor @arizeai/phoenix-otel uses under the hood:
@vercel/otel within a Next.js project.
When instrumenting a Next.js application, traced spans will not be “root spans” when the OpenInference span filter is configured. This is because Next.js parents spans underneath http requests, which do not meet the requirements to be an OpenInference span.
Examples
- AI SDK Agent: an AI SDK v7
ToolLoopAgenttraced with@arizeai/phoenix-otel - Next.js OpenAI Telemetry Example in the OpenInference repo

