Initialize once at startup
init(config?) configures the exporter against the global OpenTelemetry provider. Call it once, before anything you want traced.
isInitialized() and isGatewayConfigured() report whether the call happened and whether credentials were found.
Importing
tracing from @withgateway/sdk instead of @withgateway/sdk/tracing also wires experiment attributes onto every span. Use the root entry in a process that assigns variants.Capture LLM calls from your client
init() configures the exporter. Wrap the client and every request becomes a generation span with the model, token counts, input and output.
observeOpenAI returns the same client, so wrap it once at startup and use it everywhere. observeAnthropic does the same for the Anthropic client.
The wrappers use OpenInference instrumentation that ships with the package, so no extra install is needed. Apply them to the client instance your agent actually calls; a client the SDK never sees is not traced.
init() removes credentials such as an MCP server’s authorization_token (or authorizationToken) from every span before export, and from every property read a customSpanProcessors entry makes (at start, at end, or later through a kept reference); a value that names the key other than as a JSON key is replaced whole by [redacted: holds a credential]. The request itself is sent unchanged. On a provider you build yourself, wrap the exporting processor in SecretRedactingSpanProcessor from @withgateway/sdk/tracing.
Group a multi-step run into one trace
observe(name, fn, options?) opens a span, runs the callback inside it, and closes it. Anything traced inside nests underneath, so a loop over model and tool calls reads as one trace.
kind: "TOOL". The callback’s return value becomes the span’s output.
Attribute a run to a user
identify(userId, options?) attributes every span started after it in the same async context, and stamps the span that is already open so the in-flight trace is attributed immediately.
attributes, displayName or email also updates the user’s stored profile in the background, merging with what is already there. Profile updates need credentials; trace attribution works without them. Failures are swallowed and never produce an unhandled rejection.
Trace a Claude Agent SDK run
The Claude Agent SDK runs the agent in a separate process, so pass its message stream throughobserveClaude. It yields the same messages while emitting an agent span with a generation per turn and a tool span per tool call.
perTurn: true and each assistant turn becomes its own trace instead, carrying that turn’s generation and tool calls. Tool results feed the next turn’s input, and attributes are stamped on every turn root.
Trace several agents into different projects
One process can host agents that belong in different projects.initIsolated(config?) creates a self-contained provider with its own keys, exporter and lifecycle. It never touches the global tracer, so an app that already owns a global provider keeps it.
Spans reach an isolated provider only when they start from its tracer.
tracer, a scores client bound to the same project, flush() and shutdown(). See Scores and signals.
With the Vercel AI SDK, hand the tracer to experimental_telemetry. The metadata.sessionId and metadata.userId fields map to the platform’s session and user automatically.
Flush before the process exits
Spans are batched, so a short-lived process must flush or lose its last spans.Isolated providers are not covered by the global
flush() and shutdown(). Call handle.flush() and handle.shutdown() on each handle.Version your agent builds
There is no build file and no lockfile. Wrap tools indefineTool, register code-shipped prompts, and give init an agent id. The SDK assembles a canonical manifest, stamps a content-addressed build hash on every span, and registers the build. Registration is idempotent, so every replica of the same code is one build.
defineTool returns its input unchanged, so it composes with any framework. Define tools before init, or they do not join the build identity.
Every trace then carries gateway.agent.id, gateway.agent.version and gateway.build.hash. In continuous integration the actor, commit and pull request number are captured automatically as the build’s attribution. registerSkill, registerArtifact, assembleManifest and computeBuildHash are exported for callers that assemble a manifest themselves.
Assign an A/B variant
@withgateway/sdk/experiments assigns a stable variant for the same experiment key and user id. Initialize tracing from the root entry and spans created afterwards carry the experiment attributes.
getVariant resolves to { variant, inExperiment, experimentKey, run }. variant is null when the user is outside the experiment, and run(fn) executes a function inside the assignment’s context so nested spans inherit it.
experiments.fetch(keys?) refreshes configurations from the platform, and experiments.shutdown() flushes pending exposures before exit.
Let Surface Area gate an agent’s tools
@withgateway/sdk/security decides which tools an agent may see or call, while your framework keeps owning the native tool objects. This subpath needs @opentelemetry/api installed.
secureTools returns the same collection with hidden tools removed and the rest wrapped. Each wrapped call is authorized before it runs. A blocked call throws GatewayToolBlockedError, and a call waiting on a human throws GatewayToolApprovalRequiredError. Security attributes are stamped on the active span when tracing is installed.
Where to go next
- Tracing for the trace model and what the platform does with it.
- Scores and signals for attaching evaluation results to these traces.
- Sessions and replay for reading traced sessions back.