---
title: "Trace the Vercel AI SDK"
description: "Trace Vercel AI SDK calls, steps and tool executions in TypeScript, on AI SDK 6 or 7."
sidebar:
  label: "Vercel AI SDK"
seo:
  title: "Trace the Vercel AI SDK | Judgment Docs"
  description: "Trace Vercel AI SDK calls, steps and tool executions in TypeScript, on AI SDK 6 or 7."
---

The AI SDK already emits OpenTelemetry spans. You hand it Judgment's tracer with `Tracer.getOTELTracer()`, and Judgment maps model, tokens, input and output from both the AI SDK 6 and 7 span formats. How you hand over the tracer depends on the major version of `ai`.

## AI SDK 7: register once

AI SDK 7 registers telemetry globally with `registerTelemetry` and the `OpenTelemetry` integration from `@ai-sdk/otel`. Do it once at startup, after `Tracer.init`.

```bash
npm install judgeval ai@^7 @ai-sdk/openai@^4 @ai-sdk/otel zod
```

```typescript title="instrumentation.ts"
import { OpenTelemetry } from "@ai-sdk/otel";
import { registerTelemetry } from "ai";
import { Tracer } from "judgeval";

await Tracer.init({ projectName: "lunch-order-agent" });

registerTelemetry(new OpenTelemetry({ tracer: Tracer.getOTELTracer() }));
```

```typescript title="agent.ts"
import "./instrumentation";
import { openai } from "@ai-sdk/openai";
import { generateText, stepCountIs, tool } from "ai";
import { Tracer } from "judgeval";
import { z } from "zod";

const result = await generateText({
  model: openai("gpt-5.2"),
  tools: {
    check_delivery_eta: tool({
      description: "Get the delivery ETA for a restaurant",
      inputSchema: z.object({ restaurant: z.string() }),
      execute: async ({ restaurant }) => ({ restaurant, eta: "12:15 PM" }),
    }),
  },
  stopWhen: stepCountIs(5),
  prompt: "When would Olive & Thyme deliver lunch for 30 people?",
});

console.log(result.text);
await Tracer.shutdown();
```

## AI SDK 6: pass the tracer on each call

AI SDK 6 has no global registration. Turn on `experimental_telemetry` on every call you want traced.

```bash
npm install judgeval ai@^6 @ai-sdk/openai@^3
```

```typescript title="agent.ts"
import { openai } from "@ai-sdk/openai";
import { generateText } from "ai";
import { Tracer } from "judgeval";

await Tracer.init({ projectName: "lunch-order-agent" });

const { text } = await generateText({
  model: openai("gpt-5.2"),
  prompt: "order me mediterranean food to feed 30 hungry engineers",
  experimental_telemetry: { isEnabled: true, tracer: Tracer.getOTELTracer() },
});

console.log(text);
await Tracer.shutdown();
```

## Group calls into one trace

Each `generateText` call is its own root span unless something wraps it. To get one trace per user request, wrap the handler in `Tracer.observe`:

```typescript
import { Tracer } from "judgeval";

const handleRequest = Tracer.observe(
  async function handleRequest(message: string) {
    // call generateText / streamText here
    return message;
  },
  { spanType: "agent" },
);
```

## Short-lived scripts and servers

`await Tracer.shutdown()` flushes pending spans and then shuts the tracer down, so call it once at the end of a script or in your server's shutdown hook. A long-running server exports in the background and doesn't need it per request. To flush without shutting down (for example at the end of a serverless handler), use `await Tracer.forceFlush()`.

For OpenRouter as the model provider, turn on OpenRouter's usage accounting so cost shows up on the spans.

{/* SCREENSHOT: Traces view of one AI SDK 7 generateText call with step and tool spans, dark mode */}
