Skip to main content
The Vercel AI SDK has built-in OpenTelemetry support behind the per-call experimental_telemetry option. Moda.getVercelAITelemetry() returns a telemetry configuration that sends each call’s telemetry to Moda. Use this page when your application calls the AI SDK (the ai package); if you call the openai or @anthropic-ai/sdk clients directly, see the Node.js SDK instead.

Prerequisites

  • Node.js 18 or later
  • The moda-ai, ai, and at least one AI SDK provider package (for example @ai-sdk/openai or @ai-sdk/anthropic)
  • A Moda API key (created in the dashboard at Settings → Ingestion keys)
Examples on this page use AI SDK 4.x, the major version Moda’s integration tests run against.

Set up

1

Install packages

2

Initialize Moda once at startup

Moda.init() is async and the API key argument is required — the Node.js SDK does not read MODA_API_KEY from the environment on its own. If Moda.init() is not awaited, calls made before initialization completes are not captured.
3

Pass the telemetry configuration on every call

Add experimental_telemetry: Moda.getVercelAITelemetry() to each generateText, streamText, generateObject, and streamObject call. Telemetry is opt-in per call: AI SDK calls without experimental_telemetry are not captured.
4

Flush before exit

Call await Moda.flush() before a short-lived process exits so buffered telemetry is delivered.

generateText

app.ts
After running this, open Conversations in the dashboard. Within minutes you should see conversation session_123 containing your user message and the assistant reply, attributed to model gpt-4o.

streamText

Streaming works the same way. Telemetry is recorded when the stream completes:
stream.ts
A call is still recorded if you stop consuming the stream early, as long as the process flushes before exiting.

generateObject and streamObject

Structured output is captured as JSON on the assistant message:
classify.ts
streamObject works the same way: pass the same telemetry configuration and consume partialObjectStream.

Tool calls

Tool calls and tool results are captured as structured content blocks on the assistant message, including multi-step runs with maxSteps:
weather.ts
If a tool’s execute function throws, the AI SDK call itself still completes and the call is still captured.

Conversation and user context

getVercelAITelemetry() copies the active Moda.conversationId and Moda.userId into the telemetry metadata (as moda.conversation_id and moda.user_id) at the moment you call it. Set context first, and create a fresh configuration for each call.
If no conversation ID is set, each AI SDK call is grouped by its trace ID and appears as a separate conversation. Set an explicit conversation ID for anything multi-turn.
For sequential code, use the global properties as in the examples above. For concurrent request handlers, use the scoped helper so overlapping requests do not leak context into each other:
handler.ts

Setting IDs through metadata directly

You can also set moda.conversation_id and moda.user_id yourself in the metadata option instead of using the context APIs:
metadata.ts
If a conversation or user ID is active in Moda’s context when you call getVercelAITelemetry(), the context value overwrites the same key in your metadata.

Options

Moda.getVercelAITelemetry(options?) accepts:
boolean
default:"true"
Whether to record input data (prompts, messages). Set to false to keep sensitive inputs out of telemetry; the call is still captured, without message content.
boolean
default:"true"
Whether to record output data (completions, generated text). Set to false to keep sensitive outputs out of telemetry.
string
Identifier for the operation, used to distinguish different AI operations in your app.
object
Custom metadata attached to the call’s telemetry spans. Values may be strings, numbers, booleans, or arrays of those types. Merged with the moda.conversation_id / moda.user_id keys Moda adds from the active context.
The returned configuration is passed as-is to experimental_telemetry and includes Moda’s tracer, so no other OpenTelemetry setup is required.

Prompt attribution

To attribute a call to a managed prompt version, pass the prompt identifiers from .moda/prompts.lock.json in metadata:
triage.ts
See Prompt attribution for where these identifiers come from and how they appear in the dashboard.

Using the AI SDK alongside the openai package

Moda.init() also auto-instruments the openai and @anthropic-ai/sdk packages when they are installed. This does not double-capture AI SDK calls: the AI SDK provider packages (@ai-sdk/openai, @ai-sdk/anthropic) make their own HTTP requests and do not call through the openai or @anthropic-ai/sdk clients, so an AI SDK call is recorded only through the telemetry configuration you pass. Both capture paths can run in the same process:
  • Calls made through the AI SDK are captured when you pass experimental_telemetry, and not otherwise.
  • Calls made directly with the openai or @anthropic-ai/sdk clients are captured automatically.
The Node.js SDK has no option to disable auto-instrumentation for a single provider. Moda.init(apiKey, { enabled: false }) disables the SDK entirely. The Python SDK’s instruments / block_instruments options do not exist in Node.js.

Troubleshooting

For deeper debugging, initialize with debug: true: await Moda.init(apiKey, { debug: true }) logs exporter activity.

Next steps

  • Node.js SDK — init options, context APIs, and auto-instrumentation of provider clients.
  • Prompt attribution — link calls to managed prompt versions.
  • OpenTelemetry — the trace endpoint and attribute conventions this integration emits.
  • Conversations — how captured conversations appear in the dashboard.