From 0b245a1a58177c68d023d41a26f5f97184a64880 Mon Sep 17 00:00:00 2001 From: Vjeran Grozdanic Date: Tue, 4 Aug 2026 15:06:39 +0200 Subject: [PATCH 1/7] docs(js): clarify OpenAI instrumentation for Cloudflare and tools Add a Cloudflare Workers example for instrumentOpenAiClient, document that tool execution spans are not created by the OpenAI client wrap, and note streaming usage behavior for OpenAI-compatible providers. Refs TET-2706 --- .../configuration/integrations/openai.mdx | 69 ++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/docs/platforms/javascript/common/configuration/integrations/openai.mdx b/docs/platforms/javascript/common/configuration/integrations/openai.mdx index e32019c0bb161..cf2b92a8cc1dd 100644 --- a/docs/platforms/javascript/common/configuration/integrations/openai.mdx +++ b/docs/platforms/javascript/common/configuration/integrations/openai.mdx @@ -68,6 +68,48 @@ supported: The `instrumentOpenAiClient` helper adds instrumentation for the [`openai`](https://www.npmjs.com/package/openai) SDK to capture spans by wrapping OpenAI SDK calls and recording LLM interactions with configurable input/output recording. You need to manually wrap your OpenAI client instance with this helper. + + + On Cloudflare Workers, enable tracing on the worker (for example with `Sentry.withSentry` and `tracesSampleRate`), then wrap every OpenAI client you use. Tracing alone is not enough — unwrapped clients produce no `gen_ai.*` spans. + + ```javascript + import * as Sentry from "@sentry/cloudflare"; + import OpenAI from "openai"; + + export default Sentry.withSentry( + (env) => ({ + dsn: env.SENTRY_DSN, + tracesSampleRate: 1.0, + dataCollection: {}, + }), + { + async fetch(request, env) { + const openai = new OpenAI({ + apiKey: env.OPENAI_API_KEY, + // OpenAI-compatible providers (for example OpenRouter) work the same way: + // baseURL: "https://openrouter.ai/api/v1", + }); + + const client = Sentry.instrumentOpenAiClient(openai, { + recordInputs: true, + recordOutputs: true, + }); + + const response = await client.chat.completions.create({ + model: "gpt-4o-mini", + messages: [{ role: "user", content: "Hello!" }], + }); + + return Response.json(response); + }, + }, + ); + ``` + + + + + See example below: ```javascript @@ -90,6 +132,8 @@ supported: }); ``` + + To customize what data is captured (such as inputs and outputs), see the [Options](#options) in the Configuration section. @@ -156,14 +200,37 @@ By default, tracing support is added to the following OpenAI SDK calls: - `chat.completions.create()` - Chat completion requests - `responses.create()` - Response SDK requests -Streaming and non-streaming requests are automatically detected and handled appropriately. +Streaming and non-streaming requests are automatically detected and handled appropriately. Each call creates a `gen_ai.chat` span (including `responses.create()`). + +### What is captured + +Instrumented calls record model, token usage, latency, and (when enabled) inputs/outputs on the LLM span. If you pass `tools` to the request, Sentry stores the tool definitions on the span and records any tool calls the model returns as span attributes. + +### Tool execution spans + +The OpenAI SDK does **not** run your tools — your application does, after the model returns `tool_calls`. Because of that, `instrumentOpenAiClient` / `openAIIntegration` do **not** create `gen_ai.execute_tool` spans for local tool handlers. + +To get the full agent tree (`gen_ai.invoke_agent` → `gen_ai.chat` + `gen_ai.execute_tool`), wrap your tool loop with manual instrumentation, or use a framework integration that owns the tool loop (for example Vercel AI). + +### Streaming token usage When using OpenAI's streaming API, you must also pass `stream_options: { include_usage: true }` to receive token usage data. Without this option, OpenAI does not include `prompt_tokens` or `completion_tokens` in streamed responses, and Sentry will be unable to capture `gen_ai.usage.input_tokens` / `gen_ai.usage.output_tokens` on the resulting span. This is an OpenAI API behavior, not a Sentry limitation. See [OpenAI API reference](https://platform.openai.com/docs/api-reference/chat/create). +OpenAI-compatible providers may still return usage without `stream_options`; prefer setting `include_usage: true` whenever you need reliable token attributes. + +```javascript +const stream = await client.chat.completions.create({ + model: "gpt-4o-mini", + messages: [{ role: "user", content: "Hello!" }], + stream: true, + stream_options: { include_usage: true }, +}); +``` + ## Supported Versions - `openai`: `>=4.0.0 <7` From 1eb2c552f93b9390e003c1de958d706abb1e02b1 Mon Sep 17 00:00:00 2001 From: Vjeran Grozdanic Date: Tue, 4 Aug 2026 15:36:06 +0200 Subject: [PATCH 2/7] docs(js): drop OpenRouter notes; clarify responses spans and CF DO Explain that responses.create uses gen_ai.chat spans, add Durable Object trace propagation and Conversations links for Cloudflare. --- .../common/configuration/integrations/openai.mdx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/platforms/javascript/common/configuration/integrations/openai.mdx b/docs/platforms/javascript/common/configuration/integrations/openai.mdx index cf2b92a8cc1dd..682fc893356e9 100644 --- a/docs/platforms/javascript/common/configuration/integrations/openai.mdx +++ b/docs/platforms/javascript/common/configuration/integrations/openai.mdx @@ -86,8 +86,6 @@ supported: async fetch(request, env) { const openai = new OpenAI({ apiKey: env.OPENAI_API_KEY, - // OpenAI-compatible providers (for example OpenRouter) work the same way: - // baseURL: "https://openrouter.ai/api/v1", }); const client = Sentry.instrumentOpenAiClient(openai, { @@ -106,6 +104,10 @@ supported: ); ``` + If you call OpenAI from a Durable Object, wrap the DO with `instrumentDurableObjectWithSentry` and set `enableRpcTracePropagation: true` so Worker → DO → LLM stays on one trace. + + For multi-turn Conversations and the User column, see Tracking Conversations (`setConversationId` / `setUser`). + @@ -200,7 +202,9 @@ By default, tracing support is added to the following OpenAI SDK calls: - `chat.completions.create()` - Chat completion requests - `responses.create()` - Response SDK requests -Streaming and non-streaming requests are automatically detected and handled appropriately. Each call creates a `gen_ai.chat` span (including `responses.create()`). +Streaming and non-streaming requests are automatically detected and handled appropriately. + +Both APIs produce the same span type in Sentry: op `gen_ai.chat`, name like `chat `. There is no separate `gen_ai.responses` span — `responses.create()` is still a model chat request under the hood, so it uses the standard chat operation. ### What is captured @@ -218,8 +222,6 @@ To get the full agent tree (`gen_ai.invoke_agent` → `gen_ai.chat` + `gen_ai.ex When using OpenAI's streaming API, you must also pass `stream_options: { include_usage: true }` to receive token usage data. Without this option, OpenAI does not include `prompt_tokens` or `completion_tokens` in streamed responses, and Sentry will be unable to capture `gen_ai.usage.input_tokens` / `gen_ai.usage.output_tokens` on the resulting span. This is an OpenAI API behavior, not a Sentry limitation. See [OpenAI API reference](https://platform.openai.com/docs/api-reference/chat/create). -OpenAI-compatible providers may still return usage without `stream_options`; prefer setting `include_usage: true` whenever you need reliable token attributes. - ```javascript From 179b2bb71ef04b7a46aec3020b74ec0eddb1e922 Mon Sep 17 00:00:00 2001 From: Vjeran Grozdanic Date: Tue, 4 Aug 2026 15:39:15 +0200 Subject: [PATCH 3/7] docs(js): fix OpenAI PR review comments Remove permissive dataCollection from the Cloudflare example and gate agent-tracing / Vercel AI links so browser guides point at agent-tracing-browser instead of missing server pages. --- .../common/configuration/integrations/openai.mdx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/platforms/javascript/common/configuration/integrations/openai.mdx b/docs/platforms/javascript/common/configuration/integrations/openai.mdx index 682fc893356e9..cc22d5f717b91 100644 --- a/docs/platforms/javascript/common/configuration/integrations/openai.mdx +++ b/docs/platforms/javascript/common/configuration/integrations/openai.mdx @@ -80,7 +80,6 @@ supported: (env) => ({ dsn: env.SENTRY_DSN, tracesSampleRate: 1.0, - dataCollection: {}, }), { async fetch(request, env) { @@ -214,8 +213,18 @@ Instrumented calls record model, token usage, latency, and (when enabled) inputs The OpenAI SDK does **not** run your tools — your application does, after the model returns `tool_calls`. Because of that, `instrumentOpenAiClient` / `openAIIntegration` do **not** create `gen_ai.execute_tool` spans for local tool handlers. + + To get the full agent tree (`gen_ai.invoke_agent` → `gen_ai.chat` + `gen_ai.execute_tool`), wrap your tool loop with manual instrumentation, or use a framework integration that owns the tool loop (for example Vercel AI). + + + + +To get the full agent tree (`gen_ai.invoke_agent` → `gen_ai.chat` + `gen_ai.execute_tool`), wrap your tool loop with manual instrumentation. + + + ### Streaming token usage From 613a7777e59429f7c154e98064a174b2dd567b1e Mon Sep 17 00:00:00 2001 From: Vjeran Grozdanic Date: Wed, 5 Aug 2026 10:56:13 +0200 Subject: [PATCH 4/7] docs(js): Fix OpenAI agent-tracing links and CF RPC note Require enableRpcTracePropagation on both Worker and DO, and gate tool-execution guidance to platforms that actually host the linked pages. Refs TET-2706 Co-Authored-By: opencode --- .../common/configuration/integrations/openai.mdx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/platforms/javascript/common/configuration/integrations/openai.mdx b/docs/platforms/javascript/common/configuration/integrations/openai.mdx index cc22d5f717b91..87700591b6fb8 100644 --- a/docs/platforms/javascript/common/configuration/integrations/openai.mdx +++ b/docs/platforms/javascript/common/configuration/integrations/openai.mdx @@ -103,7 +103,7 @@ supported: ); ``` - If you call OpenAI from a Durable Object, wrap the DO with `instrumentDurableObjectWithSentry` and set `enableRpcTracePropagation: true` so Worker → DO → LLM stays on one trace. + If you call OpenAI from a Durable Object over RPC, set `enableRpcTracePropagation: true` on **both** the Worker (caller) and the DO (receiver). Wrap the DO with `instrumentDurableObjectWithSentry`. See RPC Trace Propagation. For multi-turn Conversations and the User column, see Tracking Conversations (`setConversationId` / `setUser`). @@ -213,13 +213,19 @@ Instrumented calls record model, token usage, latency, and (when enabled) inputs The OpenAI SDK does **not** run your tools — your application does, after the model returns `tool_calls`. Because of that, `instrumentOpenAiClient` / `openAIIntegration` do **not** create `gen_ai.execute_tool` spans for local tool handlers. - + To get the full agent tree (`gen_ai.invoke_agent` → `gen_ai.chat` + `gen_ai.execute_tool`), wrap your tool loop with manual instrumentation, or use a framework integration that owns the tool loop (for example Vercel AI). - + + +To get the full agent tree (`gen_ai.invoke_agent` → `gen_ai.chat` + `gen_ai.execute_tool`), use a framework integration that owns the tool loop (for example Vercel AI), or create `gen_ai.execute_tool` spans yourself around your local tool handlers. + + + + To get the full agent tree (`gen_ai.invoke_agent` → `gen_ai.chat` + `gen_ai.execute_tool`), wrap your tool loop with manual instrumentation. From 04216fe472cd301c5b48802dad7ea852093ef6ec Mon Sep 17 00:00:00 2001 From: Vjeran Grozdanic Date: Wed, 5 Aug 2026 11:11:10 +0200 Subject: [PATCH 5/7] docs(js): Drop Vercel AI cross-link from OpenAI docs OpenAI page should not steer readers to a different integration; point at manual agent instrumentation only. Refs TET-2706 Co-Authored-By: opencode --- .../common/configuration/integrations/openai.mdx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/platforms/javascript/common/configuration/integrations/openai.mdx b/docs/platforms/javascript/common/configuration/integrations/openai.mdx index 87700591b6fb8..078741e4090e3 100644 --- a/docs/platforms/javascript/common/configuration/integrations/openai.mdx +++ b/docs/platforms/javascript/common/configuration/integrations/openai.mdx @@ -215,13 +215,7 @@ The OpenAI SDK does **not** run your tools — your application does, after the -To get the full agent tree (`gen_ai.invoke_agent` → `gen_ai.chat` + `gen_ai.execute_tool`), wrap your tool loop with manual instrumentation, or use a framework integration that owns the tool loop (for example Vercel AI). - - - - - -To get the full agent tree (`gen_ai.invoke_agent` → `gen_ai.chat` + `gen_ai.execute_tool`), use a framework integration that owns the tool loop (for example Vercel AI), or create `gen_ai.execute_tool` spans yourself around your local tool handlers. +To get the full agent tree (`gen_ai.invoke_agent` → `gen_ai.chat` + `gen_ai.execute_tool`), wrap your tool loop with manual instrumentation. From d73395f394f1a7b57f700015e6ab50b636aab4b3 Mon Sep 17 00:00:00 2001 From: Vjeran Grozdanic Date: Wed, 5 Aug 2026 11:29:42 +0200 Subject: [PATCH 6/7] docs(js): Rename OpenAI client wrap section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Call the wrapper path "Instrument the Client" instead of "Manual Instrumentation" — it is the primary setup on non-Node runtimes, not hand-written spans. Refs TET-2706 Co-Authored-By: opencode --- .../common/configuration/integrations/openai.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/platforms/javascript/common/configuration/integrations/openai.mdx b/docs/platforms/javascript/common/configuration/integrations/openai.mdx index 078741e4090e3..7ea9496f83ac6 100644 --- a/docs/platforms/javascript/common/configuration/integrations/openai.mdx +++ b/docs/platforms/javascript/common/configuration/integrations/openai.mdx @@ -36,7 +36,7 @@ supported: - For meta-framework applications running on both client and server, we recommend **setting up the integration manually** using the [`instrumentOpenAiClient` wrapper](#manual-instrumentation) to ensure consistent instrumentation across all runtimes. + For meta-framework applications running on both client and server, we recommend using the [`instrumentOpenAiClient` wrapper](#instrument-the-client) to ensure consistent instrumentation across all runtimes. @@ -48,7 +48,7 @@ supported: - If you are using a different runtime (like Bun, Cloudflare Workers or a Browser) or experiencing missing spans, you need to use **[Manual Instrumentation](#manual-instrumentation)** to explicitly wrap your AI client instance instead. + If you are using a different runtime (like Bun, Cloudflare Workers or a Browser) or experiencing missing spans, **[wrap the client](#instrument-the-client)** with `instrumentOpenAiClient` instead. @@ -62,11 +62,11 @@ supported: - ## Manual Instrumentation + ## Instrument the Client _Import name: `Sentry.instrumentOpenAiClient`_ - The `instrumentOpenAiClient` helper adds instrumentation for the [`openai`](https://www.npmjs.com/package/openai) SDK to capture spans by wrapping OpenAI SDK calls and recording LLM interactions with configurable input/output recording. You need to manually wrap your OpenAI client instance with this helper. + The `instrumentOpenAiClient` helper instruments the [`openai`](https://www.npmjs.com/package/openai) SDK by wrapping your client instance and recording LLM interactions with configurable input/output capture. @@ -184,7 +184,7 @@ Sentry.init({ -Using the `instrumentOpenAiClient` wrapper for **manual instrumentation**: +Using the `instrumentOpenAiClient` wrapper: ```javascript const client = Sentry.instrumentOpenAiClient(openai, { From d5768684c3a7f545a6652d9ae1be1be6f53337fc Mon Sep 17 00:00:00 2001 From: Vjeran Grozdanic Date: Thu, 6 Aug 2026 13:35:27 +0200 Subject: [PATCH 7/7] docs(js): Remove redundant OpenAI heading Keep the captured data paragraph as a continuation of the supported operations section. Co-Authored-By: OpenCode --- .../javascript/common/configuration/integrations/openai.mdx | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/platforms/javascript/common/configuration/integrations/openai.mdx b/docs/platforms/javascript/common/configuration/integrations/openai.mdx index 7ea9496f83ac6..a1cc1662868f3 100644 --- a/docs/platforms/javascript/common/configuration/integrations/openai.mdx +++ b/docs/platforms/javascript/common/configuration/integrations/openai.mdx @@ -205,8 +205,6 @@ Streaming and non-streaming requests are automatically detected and handled appr Both APIs produce the same span type in Sentry: op `gen_ai.chat`, name like `chat `. There is no separate `gen_ai.responses` span — `responses.create()` is still a model chat request under the hood, so it uses the standard chat operation. -### What is captured - Instrumented calls record model, token usage, latency, and (when enabled) inputs/outputs on the LLM span. If you pass `tools` to the request, Sentry stores the tool definitions on the span and records any tool calls the model returns as span attributes. ### Tool execution spans