Skip to content

Tracing

Last updated View as MarkdownAgent setup

Agent tracing helps you understand what an agent did at every turn, including its model calls, tool runs, and approval requests. Use traces to investigate unexpected behavior, find slow operations, and review token usage.

Agent activity appears alongside runtime events such as fetch calls, KV reads, and D1 queries in Workers traces.

Enable tracing

Enable tracing in your Wrangler configuration:

{
  "$schema": "./node_modules/wrangler/config-schema.json",
  "observability": {
    "traces": {
      "enabled": true
    }
  }
}
[observability.traces]
enabled = true

View agent activity

Open the Agents tab in the Cloudflare Dashboard to see traced agents and subagents. The overview shows each agent's model, session count, runs, and total token usage.

A session is a conversation made up of one or more turns. A turn is one request to an agent and its response.

Agents dashboard showing agents with session, run, and token totals

Select an agent to see its traces. Each trace includes its duration, token breakdown, and status.

Agent details showing recent traces and token totals

There are two ways to follow what an agent did: Session replay and Trace.

Session replay shows the recorded conversation across turns, including messages, reasoning, tool calls, and subagent activity. What appears depends on your payload recording settings.

Session replay showing messages, reasoning, and subagent tool calls

Trace is a waterfall of the operations performed during one turn. It shows when each operation started, how long it took, and which operation called it.

Trace waterfall showing nested agent, model, tool, and D1 spans

Trace structure

Each turn produces a trace made of spans, one for each timed operation:

invoke_agent {agent class}
├── chat {model}
└── execute_tool {tool}
    └── tool_approval {tool}

The invoke_agent span covers the turn. Model calls, tool runs, and approvals appear as nested spans. Subagent work appears under the operation that invoked it.

Agent identity

Agent spans use three fields to identify the work shown in the dashboard:

  • Agent name identifies the logical agent implementation. Use a shared name such as booking-agent.
  • Agent ID identifies the stable agent instance or resource, such as booking-agent-production.
  • Conversation ID identifies the current conversation or session.

Do not derive the agent name from a request, conversation, or user identifier. This creates too many distinct agent names in the dashboard.

Payload privacy

Message and tool payloads can contain personally identifiable information. Only record payloads that are safe to store. Each integration controls payload recording differently, so configure it in the relevant Framework setup section.

Think and wrapAISDK() use storeMessages to record input and output messages on chat spans. They use storeTools to record arguments and results on execute_tool spans.

Framework setup

Tracing and payload controls depend on the integration. Think and Flue instrument turns automatically. Direct AI SDK calls and custom harnesses need additional setup.

Think

Think automatically instruments your agent and emits the standard span structure. No additional tracing setup is required.

Store payloads

Think does not store message or tool payloads by default. To record them, override the properties on the agent class:

import { Think } from "@cloudflare/think";

export class MyAgent extends Think {
	storeMessages = true;
	storeTools = true;
}
import { Think } from "@cloudflare/think";

export class MyAgent extends Think<Env> {
	override storeMessages = true;
	override storeTools = true;
}

Flue

Flue v2+ also automatically instruments your agent and emits the standard span structure. No additional tracing setup is required.

Exclude payloads

Flue stores messages, system instructions, tool definitions, arguments, and results by default. To stop recording them, set content to false:

import { instrument } from "@flue/runtime";
import { createCloudflareTracing } from "@flue/runtime/cloudflare";

instrument(createCloudflareTracing({ content: false }));
import { instrument } from "@flue/runtime";
import { createCloudflareTracing } from "@flue/runtime/cloudflare";

instrument(createCloudflareTracing({ content: false }));

AI SDK

For direct AI SDK calls, wrap the namespace once:

import * as ai from "ai";
import { wrapAISDK } from "agents/observability/ai";

const tracedAI = wrapAISDK(ai);
import * as ai from "ai";
import { wrapAISDK } from "agents/observability/ai";

const tracedAI = wrapAISDK(ai);

wrapAISDK() supports AI SDK v6 and v7. It instruments generateText, streamText, generateObject, and streamObject, creating the invoke_agent parent before model and tool work begins.

Unlike Think, a direct AI SDK call has no Agent instance from which to infer dashboard identity. Supply the agent identity fields on each call.

Only include context that is safe to store. Do not include credentials, tokens, user input, or other secrets.

AI SDK v7

Use native AI SDK v7 telemetry fields to supply identity. You can include additional scalar context, such as a tenant or route, to make traces easier to query:

await tracedAI.generateText({
	model,
	prompt: "Find an available appointment",
	runtimeContext: {
		agentId: "booking-agent-production",
		conversationId: "conversation-123",
		tenantId: "tenant-42",
	},
	telemetry: {
		functionId: "booking-agent",
		includeRuntimeContext: {
			agentId: true,
			conversationId: true,
			tenantId: true,
		},
	},
});
await tracedAI.generateText({
	model,
	prompt: "Find an available appointment",
	runtimeContext: {
		agentId: "booking-agent-production",
		conversationId: "conversation-123",
		tenantId: "tenant-42",
	},
	telemetry: {
		functionId: "booking-agent",
		includeRuntimeContext: {
			agentId: true,
			conversationId: true,
			tenantId: true,
		},
	},
});

This maps functionId, agentId, and conversationId to gen_ai.agent.name, gen_ai.agent.id, and gen_ai.conversation.id. Other included scalar values use the cloudflare.agents.runtime_context.* namespace.

AI SDK v6

AI SDK v6 uses experimental_telemetry.metadata for the same identity and additional span data:

await tracedAI.generateText({
	model,
	prompt: "Find an available appointment",
	experimental_telemetry: {
		functionId: "booking-agent",
		metadata: {
			agentId: "booking-agent-production",
			conversationId: "conversation-123",
			tenantId: "tenant-42",
		},
	},
});
await tracedAI.generateText({
	model,
	prompt: "Find an available appointment",
	experimental_telemetry: {
		functionId: "booking-agent",
		metadata: {
			agentId: "booking-agent-production",
			conversationId: "conversation-123",
			tenantId: "tenant-42",
		},
	},
});

Additional scalar metadata uses the cloudflare.agents.metadata.* namespace.

Store payloads

wrapAISDK() does not store message or tool payloads by default. To record them with AI SDK v6 or v7, pass storage options when wrapping the namespace:

import * as ai from "ai";
import { wrapAISDK } from "agents/observability/ai";

const tracedAI = wrapAISDK(ai, {
	storeMessages: true,
	storeTools: true,
});
import * as ai from "ai";
import { wrapAISDK } from "agents/observability/ai";

const tracedAI = wrapAISDK(ai, {
	storeMessages: true,
	storeTools: true,
});

Custom harnesses

If your agent does not use one of our currently supported frameworks, instrument it with the Workers custom spans API. Create an invoke_agent span for each turn, with chat spans for model calls, execute_tool spans for tool runs, and tool_approval spans for approvals.

For span names, attributes, and implementation examples, refer to the OpenTelemetry GenAI reference implementations. Adapt these examples to the Workers custom spans API.

Add agent identity

Add these attributes to both the invoke_agent and chat spans so the Agents dashboard can associate the telemetry with the agent and conversation:

Attribute invoke_agent span chat span
gen_ai.operation.name invoke_agent chat
gen_ai.agent.name A shared agent name, such as booking-agent The same agent name
gen_ai.agent.id A stable identifier for the agent instance The same agent ID
gen_ai.conversation.id The conversation, session, or thread identifier The same conversation, session, or thread ID

Store payloads

For custom spans, add payload attributes manually. Use gen_ai.input.messages, gen_ai.output.messages, and gen_ai.system_instructions on model spans. Use gen_ai.tool.call.arguments and gen_ai.tool.call.result on tool spans. The custom spans API accepts scalar attribute values, so serialize structured payloads with JSON.stringify(). These values are recorded whenever the invocation is sampled. Only add payloads that are safe to store.

Exporting traces

Span attributes follow the OpenTelemetry Generative AI semantic conventions, so any tool that reads OpenTelemetry data can consume them. To send traces to an external destination, configure an OpenTelemetry Protocol (OTLP) endpoint in Workers Observability.

Pricing

Agent traces use Workers tracing and follow Workers Observability pricing.

The Agents view shows your agent's operations. The full Worker trace may include additional spans from SDK internals and other Worker-level operations. To inspect the full trace, select View in Observability.

Every span counts as one observability event, including spans not shown in the Agents view. Tracing is free while in beta. Beginning October 1, 2026, tracing will be included in existing Workers Observability pricing:

Tier Included events Retention
Workers Free 200,000 per day 3 days
Workers Paid 20 million per month ($0.60 per additional million) 7 days

Limitations

  • Use agent traces for debugging and observability. Traces are not a complete or lossless record of a conversation.
  • Payload data is subject to span size limits. Long messages, reasoning, tool arguments, and results may be truncated. These limits may change.
  • Session replay does not display images.

Next steps

Diagnostics channels

Subscribe to structured agent events for state changes, schedules, workflows, and more.

Agents API

Complete API reference for the Agents SDK.

Was this helpful?