Skip to content

Vercel AI SDK

The Vercel AI SDK can emit OpenTelemetry spans for model calls, tools, token usage, and streaming operations. Logfire can receive those spans through either @pydantic/logfire-node in Node.js scripts or @vercel/otel in Next.js applications.

Since AI SDK v7, the recommended telemetry path is the @ai-sdk/otel package, which emits spans that follow the OpenTelemetry GenAI semantic conventions (gen_ai.*). AI SDK v6 and earlier used the per-call experimental_telemetry option and the legacy ai.* attribute shape. Logfire recognizes both, so existing instrumentation keeps working — the sections below cover each path.

Node.js Scripts (AI SDK v7)

Terminal
npm install @pydantic/logfire-node ai @ai-sdk/otel @ai-sdk/openai

Replace @ai-sdk/openai with the provider package you use, such as @ai-sdk/anthropic or @ai-sdk/google.

Configure Logfire before importing the AI SDK:

instrumentation.ts
import * as logfire from '@pydantic/logfire-node'

logfire.configure({
  serviceName: 'ai-worker',
})

Register the @ai-sdk/otel integration once at startup. After that, every AI SDK call emits telemetry — you do not set experimental_telemetry per call:

import './instrumentation.ts'
import { OpenTelemetry } from '@ai-sdk/otel'
import { openai } from '@ai-sdk/openai'
import { generateText, registerTelemetry } from 'ai'

// Register once for the whole process.
registerTelemetry(new OpenTelemetry())

const result = await generateText({
  model: openai('gpt-4.1-mini'),
  prompt: 'Write a short haiku about traces.',
})

console.log(result.text)

@ai-sdk/otel exports two integrations:

  • OpenTelemetry — emits GenAI semantic-convention spans (gen_ai.*). Recommended, and what Logfire renders and prices best.
  • LegacyOpenTelemetry — emits the older AI SDK (ai.*) span shape for tools that have not migrated.

Next.js

In Next.js, configure @vercel/otel as shown in Next.js, then register @ai-sdk/otel in the same instrumentation.ts. The instrumentation.ts file must live in the project root, or in src if your Next.js app uses src.

Terminal
npm install @vercel/otel @opentelemetry/api ai @ai-sdk/otel @ai-sdk/openai

Legacy Telemetry (AI SDK v6 and earlier)

Before v7, the Vercel AI SDK emitted spans only when experimental_telemetry.isEnabled was set on each call:

const result = await generateText({
  model,
  prompt: 'Write a short haiku about traces.',
  experimental_telemetry: { isEnabled: true },
})

This still works and covers the AI SDK core functions that emit telemetry, including:

  • generateText and streamText
  • generateObject and streamObject
  • embed and embedMany

These calls produce the legacy ai.* attribute shape (for example ai.model.provider, ai.response.model, ai.usage.promptTokens). Logfire maps both the legacy ai.* attributes and the v7 gen_ai.* attributes, so spans from either version are recognized as LLM spans.

Example: Text Generation With Tools

import './instrumentation.ts'
import { OpenTelemetry } from '@ai-sdk/otel'
import { openai } from '@ai-sdk/openai'
import { generateText, registerTelemetry, tool } from 'ai'
import { z } from 'zod'

registerTelemetry(new OpenTelemetry())

const result = await generateText({
  model: openai('gpt-4.1-mini'),
  tools: {
    weather: tool({
      description: 'Get the weather in a location',
      inputSchema: z.object({
        location: z.string().describe('The location to get the weather for'),
      }),
      execute: async ({ location }) => ({
        location,
        temperature: 72,
      }),
    }),
  },
  prompt: 'What is the weather in San Francisco?',
})

console.log(result.text)

For Node.js scripts, import your Logfire instrumentation file before importing or calling the AI SDK.

What You Will See

When telemetry is enabled, Logfire captures a trace for each AI operation. With @ai-sdk/otel (v7), span names include the model name, so a single generateText call with a tool produces spans such as:

  • invoke_agent gpt-4.1-mini — the root agent span
  • chat gpt-4.1-mini — the provider/model call
  • execute_tool weather — a tool call

Depending on the AI SDK provider and call type, traces can also include:

  • model and provider details (gen_ai.provider.name, gen_ai.request.model / gen_ai.response.model)
  • input and output token usage
  • timing information
  • tool call arguments and results
  • prompts and responses (gen_ai.input.messages / gen_ai.output.messages) when the AI SDK emits them

Prompts and responses may contain sensitive data. To emit telemetry without recording inputs or outputs for a v7 call, set both options to false:

await generateText({
  model,
  prompt,
  telemetry: {
    recordInputs: false,
    recordOutputs: false,
  },
})

Set telemetry.isEnabled to false to disable telemetry entirely for an individual call.

Metadata

Use functionId and metadata to make traces easier to query. In v7, pass them through the per-call telemetry option:

await generateText({
  model,
  prompt,
  telemetry: {
    functionId: 'support-reply',
    metadata: {
      tenant: 'acme',
    },
  },
})

functionId identifies the agent or use case behind a call. Logfire uses it as the agent identity when grouping runs (for example on the AI Engineering agent pages), rather than it only appearing in span names — in v7 the span name carries the model, not the functionId. metadata attaches custom key-value pairs to the emitted telemetry spans.

For AI SDK v6 and earlier, pass the same fields inside experimental_telemetry:

await generateText({
  model,
  prompt,
  experimental_telemetry: {
    functionId: 'support-reply',
    isEnabled: true,
    metadata: {
      tenant: 'acme',
    },
  },
})