Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ supported:

<PlatformSection supported={["javascript.nextjs", "javascript.nuxt", "javascript.solidstart", "javascript.sveltekit", "javascript.react-router", "javascript.remix", "javascript.astro", "javascript.tanstackstart-react"]}>
<Alert level="warning">
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.
</Alert>
</PlatformSection>

Expand All @@ -48,7 +48,7 @@ supported:

<PlatformSection notSupported={["javascript.node", "javascript.connect", "javascript.hapi", "javascript.koa"]}>
<Alert>
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.
</Alert>
</PlatformSection>

Expand All @@ -62,11 +62,54 @@ supported:

<PlatformSection notSupported={["javascript.node", "javascript.connect", "javascript.hapi", "javascript.koa"]}>

## 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.

<PlatformSection supported={["javascript.cloudflare"]}>

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,
}),
{
async fetch(request, env) {
const openai = new OpenAI({
apiKey: env.OPENAI_API_KEY,
});

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);
},
},
);
```

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 <PlatformLink to="/features/durableobject/">`instrumentDurableObjectWithSentry`</PlatformLink>. See <PlatformLink to="/tracing/distributed-tracing/#rpc-trace-propagation">RPC Trace Propagation</PlatformLink>.

For multi-turn Conversations and the User column, see <PlatformLink to="/agent-tracing/#tracking-conversations">Tracking Conversations</PlatformLink> (`setConversationId` / `setUser`).

</PlatformSection>

<PlatformSection notSupported={["javascript.cloudflare"]}>

See example below:

Expand All @@ -90,6 +133,8 @@ supported:
});
```

</PlatformSection>

To customize what data is captured (such as inputs and outputs), see the [Options](#options) in the Configuration section.

</PlatformSection>
Expand Down Expand Up @@ -139,7 +184,7 @@ Sentry.init({

<PlatformSection notSupported={["javascript.node", "javascript.connect", "javascript.hapi", "javascript.koa"]}>

Using the `instrumentOpenAiClient` wrapper for **manual instrumentation**:
Using the `instrumentOpenAiClient` wrapper:

```javascript
const client = Sentry.instrumentOpenAiClient(openai, {
Expand All @@ -158,12 +203,43 @@ By default, tracing support is added to the following OpenAI SDK calls:

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 <model>`. 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.
Comment thread
vgrozdanic marked this conversation as resolved.

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.

<PlatformSection supported={["javascript.node", "javascript.aws-lambda", "javascript.azure-functions", "javascript.connect", "javascript.express", "javascript.fastify", "javascript.gcp-functions", "javascript.hapi", "javascript.hono", "javascript.koa", "javascript.nestjs", "javascript.bun", "javascript.nextjs", "javascript.nuxt", "javascript.astro", "javascript.solidstart", "javascript.sveltekit", "javascript.remix", "javascript.cloudflare", "javascript.tanstackstart-react"]}>

To get the full agent tree (`gen_ai.invoke_agent` → `gen_ai.chat` + `gen_ai.execute_tool`), wrap your tool loop with <PlatformLink to="/agent-tracing/manual-instrumentation/">manual instrumentation</PlatformLink>.

</PlatformSection>

<PlatformSection supported={["javascript", "javascript.angular", "javascript.ember", "javascript.gatsby", "javascript.react", "javascript.solid", "javascript.svelte", "javascript.vue"]}>

To get the full agent tree (`gen_ai.invoke_agent` → `gen_ai.chat` + `gen_ai.execute_tool`), wrap your tool loop with <PlatformLink to="/agent-tracing-browser/">manual instrumentation</PlatformLink>.

</PlatformSection>
Comment thread
vgrozdanic marked this conversation as resolved.

### Streaming token usage

<Alert>

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).

</Alert>

```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`
Loading