diff --git a/docs/platforms/javascript/guides/cloudflare/features/agents-sdk.mdx b/docs/platforms/javascript/guides/cloudflare/features/agents-sdk.mdx
index 0081899975799..df3090650158f 100644
--- a/docs/platforms/javascript/guides/cloudflare/features/agents-sdk.mdx
+++ b/docs/platforms/javascript/guides/cloudflare/features/agents-sdk.mdx
@@ -1,22 +1,44 @@
---
title: Cloudflare Agents SDK
-description: "Link Cloudflare Agents SDK chats to Sentry Conversations with a chat session ID."
+description: "Instrument Cloudflare Agents SDK classes with Sentry and link chats to Conversations."
---
-When you build agents with the [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/), set a conversation ID so multi-turn AI activity groups correctly in Conversations.
+
-Use **your chat session ID** (for example a UUID or `conv_...` value your app creates when the user starts a chat). Do not use a user ID, room name, or the Durable Object instance name unless that name is already one chat session.
+When you build agents with the [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/), wrap your agent classes with `instrumentAgentWithSentry`. Agents are Durable Objects under the hood, so the wrapper applies everything Durable Object instrumentation does (request transactions, alarms, WebSocket handlers, RPC trace propagation), plus agent-specific telemetry:
-Workers AI does **not** set this for you. Set the ID on the isolation scope that runs your AI work — for chat agents, that is typically at the start of `onChatMessage`, before any model or tool calls.
+- **Callable RPC spans**: a span for each `@callable()` method invoked over WebSocket, carrying the agent class and instance name as attributes.
+- **Automatic conversation IDs**: the SDK sets the conversation ID on every chat turn (`onChatMessage`) and every callable RPC call, so `gen_ai` spans group in Conversations without any `setConversationId` call.
-## Prerequisites
+```typescript
+import * as Sentry from "@sentry/cloudflare";
+import { Agent, callable } from "agents";
+
+class MyAgentBase extends Agent {
+ @callable()
+ async greet(name: string): Promise {
+ return `Hello, ${name}!`;
+ }
+}
+
+// Export your named class as defined in your wrangler config
+export const MyAgent = Sentry.instrumentAgentWithSentry(
+ (env: Env) => ({
+ dsn: "___PUBLIC_DSN___",
+ tracesSampleRate: 1.0,
+ enableRpcTracePropagation: true,
+ }),
+ MyAgentBase
+);
+```
-- Tracing enabled
-- Durable Objects instrumented with `instrumentDurableObjectWithSentry` (see Durable Objects)
+`instrumentAgentWithSentry` works with `Agent` from `agents`, `AIChatAgent` from `@cloudflare/ai-chat`, and `McpAgent` from `agents/mcp`. When you build with the Sentry Cloudflare Vite plugin's `autoInstrumentation`, the plugin detects and wraps Agent classes automatically.
-## Link conversations
+## Conversation IDs
-Set the conversation ID before any AI calls in the chat handler:
+The automatic conversation ID defaults to the **agent instance name**, which is correct when one agent instance is one chat session (for example `useAgent({ name: chatSessionId })`). When the chat is cleared (`clearHistory()` from `useAgentChat`, or anything that emits the [`message:clear` observability event](https://developers.cloudflare.com/agents/runtime/operations/observability/#channels)), the SDK rotates to a fresh conversation ID, so a reset chat groups as a new conversation.
+
+If your instances are per-user or a shared singleton like `"default"`, the default would group unrelated chats into one conversation. Override it with your own chat session ID at the start of `onChatMessage`, before any model or tool calls:
```typescript
import * as Sentry from "@sentry/cloudflare";
@@ -30,6 +52,25 @@ class MyChatAgentBase extends AIChatAgent {
// … run your model and tools …
}
}
+```
+
+Use a real chat session ID, such as a UUID or `conv_...` value your app creates when the user starts a chat. Do not use a user ID or room name: those group unrelated chats into one conversation. To clear the ID, call `Sentry.setConversationId(null)`.
+
+## SDK Versions Before 10.69.0
+
+On older SDK versions, wrap agent classes with `instrumentDurableObjectWithSentry` instead and set the conversation ID manually at the start of the handler (`onRequest` for `Agent`, `onChatMessage` for `AIChatAgent`), before any AI calls:
+
+```typescript
+import * as Sentry from "@sentry/cloudflare";
+import { AIChatAgent } from "@cloudflare/ai-chat";
+
+class MyChatAgentBase extends AIChatAgent {
+ async onChatMessage() {
+ Sentry.setConversationId("conv_abc123");
+
+ // … run your model and tools …
+ }
+}
export const MyChatAgent = Sentry.instrumentDurableObjectWithSentry(
(env: Env) => ({
@@ -40,18 +81,6 @@ export const MyChatAgent = Sentry.instrumentDurableObjectWithSentry(
);
```
-Define the conversation ID however your app tracks chats (client param, storage, etc.). Re-set it at the start of each handler that performs AI work so it applies on that isolation scope.
-
-If you already name each agent instance as one chat session (for example `useAgent({ name: chatSessionId })`), you can pass that value:
-
-```typescript
-Sentry.setConversationId(this.name);
-```
-
-Only do this when the instance name is **one conversation**, not per-user or a shared singleton like `"default"`.
-
-To clear the ID: `Sentry.setConversationId(null)`.
-
## Users
Populate the Conversations **User** column with `Sentry.setUser` on every request or handler that performs AI calls, before those calls run. See Tracking Conversations.
@@ -60,5 +89,8 @@ Populate the Conversations **User** column with `Sentry.setUser` on every reques
- Workers AI
- Durable Objects
-- Tracking Conversations
+- Vite Plugin
+-
+ Tracking Conversations
+
- Conversations product docs
diff --git a/docs/platforms/javascript/guides/cloudflare/features/durableobject.mdx b/docs/platforms/javascript/guides/cloudflare/features/durableobject.mdx
index 229d6cf0d3d32..eb43577074881 100644
--- a/docs/platforms/javascript/guides/cloudflare/features/durableobject.mdx
+++ b/docs/platforms/javascript/guides/cloudflare/features/durableobject.mdx
@@ -28,25 +28,13 @@ export const MyDurableObject = Sentry.instrumentDurableObjectWithSentry(
`instrumentDurableObjectWithSentry` works with any class that extends `DurableObject`, not only those that extend it directly. This includes classes built on top of Durable Objects by other libraries.
-For example, the [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/) builds its `Agent` and `AIChatAgent` classes on top of Durable Objects, so you can instrument them the same way:
+For classes built on the [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/) (`Agent`, `AIChatAgent`, `McpAgent`), use the dedicated `instrumentAgentWithSentry` wrapper instead (SDK version 10.69.0 or higher). It applies the same Durable Object instrumentation and adds spans for `@callable()` RPC methods as well as automatic conversation IDs. See Cloudflare Agents SDK.
-```typescript
-import * as Sentry from "@sentry/cloudflare";
-import { Agent } from "agents";
+## Durable Object Storage Spans
-class MyAgentBase extends Agent {
- // impl
-}
+`instrumentDurableObjectWithSentry` automatically instruments Durable Object storage operations (`get`, `put`, `delete`, `list`). Each storage operation creates a span.
-// Export your named class as defined in your wrangler config
-export const MyAgent = Sentry.instrumentDurableObjectWithSentry(
- (env: Env) => ({
- dsn: "___PUBLIC_DSN___",
- tracesSampleRate: 1.0,
- }),
- MyAgentBase
-);
-```
+The SDK also filters out framework-internal storage operations (version 10.69.0 or higher): keys prefixed with `cf_`, `cf:`, `__ps_`, or `/` (used internally by the Agents SDK and PartyServer) don't create spans, so your traces show only your own storage access.
## RPC Trace Propagation
diff --git a/docs/platforms/javascript/guides/cloudflare/features/vite-plugin.mdx b/docs/platforms/javascript/guides/cloudflare/features/vite-plugin.mdx
index d2b225f8f6124..b2db9d3069720 100644
--- a/docs/platforms/javascript/guides/cloudflare/features/vite-plugin.mdx
+++ b/docs/platforms/javascript/guides/cloudflare/features/vite-plugin.mdx
@@ -6,14 +6,14 @@ description: "Learn how to use the Sentry Cloudflare Vite plugin to instrument b
- The Sentry Cloudflare Vite plugin has **experimental** stability. Configuration
- options and behavior may change or be removed in any release.
+ The Sentry Cloudflare Vite plugin has **experimental** stability.
+ Configuration options and behavior may change or be removed in any release.
The Sentry Cloudflare Vite plugin (`sentryCloudflareVitePlugin`) instruments your Worker at build time. It can:
-1. **Instrument bundled dependencies** — automatically instruments supported packages in your bundle (such as database clients like `mysql`) at build time, giving you more traces out of the box.
-2. **Auto-instrument your Worker entry** — optionally wraps your default export with `Sentry.withSentry()` and Durable Objects with `instrumentDurableObjectWithSentry()` at build time, so you don't need to modify your code.
+1. **Instrument bundled dependencies**: automatically instruments supported packages in your bundle (such as database clients like `mysql`) at build time, giving you more traces out of the box.
+2. **Auto-instrument your Worker entry**: optionally wraps your default export with `Sentry.withSentry()`, and Durable Object, Workflow, and Agents SDK classes with the matching `instrument*WithSentry` helper at build time, so you don't need to modify your code.
**We recommend building your Cloudflare Worker with Vite and the `sentryCloudflareVitePlugin` plugin.** It's the most complete way to get tracing for bundled dependencies in the Workers runtime. If you already deploy with `wrangler` directly, see [Migrating From Wrangler](#migrating-from-wrangler).
@@ -65,7 +65,7 @@ export default Sentry.withSentry(
### Auto-instrumentation (Experimental)
-Alternatively, the plugin can wrap your Worker for you at build time, so you don't need `withSentry` in your code. Enable `autoInstrumentation` and the plugin reads your `wrangler.(jsonc|toml)` to find the entry point, Durable Objects, and workflows:
+Alternatively, the plugin can wrap your Worker for you at build time, so you don't need `withSentry` in your code. Enable `autoInstrumentation` and the plugin reads your wrangler config (probing `wrangler.json`, `wrangler.jsonc`, and `wrangler.toml` at the Vite root, or the file set with [`wranglerConfigPath`](#options)) to find the entry point, Durable Objects, workflows, and Agents SDK classes. The plugin wraps Agents SDK classes (`Agent`, `AIChatAgent`, `McpAgent`) with `instrumentAgentWithSentry` (SDK version 10.69.0 or higher), which also gives them automatic conversation IDs (see Cloudflare Agents SDK).
```typescript {filename:vite.config.ts}
import { cloudflare } from "@cloudflare/vite-plugin";
@@ -100,6 +100,26 @@ If no `instrument.server.*` file exists, the SDK reads all configuration (DSN, r
## Options
+
+
+Path to your wrangler config file. By default the plugin probes `wrangler.json`, `wrangler.jsonc`, and `wrangler.toml` at the Vite root. Set this when your config lives at a custom path, for example to mirror the `configPath` option of the Cloudflare Vite plugin:
+
+```typescript {filename:vite.config.ts}
+export default defineConfig({
+ plugins: [
+ cloudflare({ configPath: "./wrangler.agent.jsonc" }),
+ sentryCloudflareVitePlugin({
+ wranglerConfigPath: "./wrangler.agent.jsonc",
+ _experimental: {
+ autoInstrumentation: true,
+ },
+ }),
+ ],
+});
+```
+
+
+
Experimental options that may change or be removed without notice.
@@ -108,7 +128,7 @@ Experimental options that may change or be removed without notice.
-Automatically wraps your Worker at build time so you don't have to edit your entry. The plugin reads your wrangler config, wraps the default export with `Sentry.withSentry()` (sourcing options from a co-located `instrument.server.*` file, falling back to `env`), and wraps any configured Durable Object and Workflow classes with the matching `instrument*WithSentry` helper. Both `vite build` and `vite dev` are instrumented.
+Automatically wraps your Worker at build time so you don't have to edit your entry. The plugin reads your wrangler config, wraps the default export with `Sentry.withSentry()` (sourcing options from a co-located `instrument.server.*` file, falling back to `env`), and wraps configured classes with the matching helper: Durable Objects with `instrumentDurableObjectWithSentry`, Workflows with `instrumentWorkflowWithSentry`, and Agents SDK classes with `instrumentAgentWithSentry` (SDK version 10.69.0 or higher). Both `vite build` and `vite dev` are instrumented.
@@ -125,4 +145,4 @@ If you deploy with `wrangler` directly, moving to Vite is straightforward:
1. Set up the [Cloudflare Vite plugin](https://developers.cloudflare.com/workers/vite-plugin/get-started/) and add a `vite.config.ts` with the `cloudflare()` and `sentryCloudflareVitePlugin()` plugins as shown above.
2. Run `vite build` before `wrangler deploy`, and use `vite dev` in place of `wrangler dev` for local development.
-Your existing `wrangler.jsonc` becomes the input config — the plugin generates the deployed output during the build. For the full list of fields that change or become redundant, see Cloudflare's [Migrating from Wrangler](https://developers.cloudflare.com/workers/vite-plugin/reference/migrating-from-wrangler-dev/) guide.
+Your existing `wrangler.jsonc` becomes the input config, and the plugin generates the deployed output during the build. For the full list of fields that change or become redundant, see Cloudflare's [Migrating from Wrangler](https://developers.cloudflare.com/workers/vite-plugin/reference/migrating-from-wrangler-dev/) guide.