Can I trace the OpenAI API without changing my code?
Yes, Rius traces your OpenAI client calls without edits to your call sites. Install the Rius integration for OpenAI, call init() once at startup, and keep using the client as before. Each chat completion shows up in the console with model, tokens, cost and messages. Manual spans are optional and add what the integration does not record.
How it works
Auto-instrumentation patches the OpenAI client library for the whole process, so every call from anywhere in your code is traced. In Python, init() detects the installed extra. In TypeScript, it enables the integration when the OpenInference OpenAI package is installed.
This is what each call carries:
- An LLM-kind span with the model, token usage and input and output messages.
- Cost, which Rius computes from the model and token counts. You never send a cost value. Costs are list-price estimates in US dollars.
- Canonical keys. The SDK rewrites the keys the integration writes onto the OpenTelemetry GenAI keys a manual generation carries, including request parameters, finish reasons, the completion id and tool definitions. This always runs.
- Errors. A call OpenAI rejects, such as a 404 for an unknown model, a 429 or a timeout, becomes an ERROR span. Its
error.typenames the error class, for exampleopenai.NotFoundError. - Time to first token on streamed calls in Python, with no manual code.
When a wrapper such as LangChain, LiteLLM or LlamaIndex sits over an OpenAI call, the SDK counts the call’s tokens and cost once. The auto-instrumentation page lists the few setups that still count a call twice, each with a fix.
Prompt and response content follows your privacy controls. capture_content=False (captureContent: false in TypeScript) and masking apply to instrumented calls exactly as they do to manual ones.
Set it up
-
Install the integration. In Python, the extra installs the instrumentation, not
openaiitself, so nameopenaifor a fresh environment:pip install "glassflow-rius[openai]" openaiIn TypeScript, the integration is an optional peer package that you install yourself:
npm install @arizeai/openinference-instrumentation-openai -
Call
init()once, before you create the client. This single call is the only addition to your code:import rius from openai import OpenAI rius.init(api_key="ri_...", service_name="my-agent") client = OpenAI() # use the client exactly as beforeimport { init } from '@glassflow-ai/rius' import OpenAI from 'openai' const rius = init({ apiKey: 'ri_...', serviceName: 'my-agent' }) const client = new OpenAI() // use the client exactly as before -
In TypeScript, check the patch with
await rius.ready, which resolves with the integrations that attached. Check thatopenaiis among them. In a CommonJS app, requireopenaibeforeinit(), or the calls stay untraced. -
On a pnpm app deployed to a file-tracing host, such as a Vercel function, the SDK may not find the package. Pass the modules you import with
instrumentModules, as shown under pnpm and serverless deployments. -
For streamed calls, ask OpenAI to send usage with the final chunk. Without it, a streamed span has no token counts and so no cost:
stream = client.chat.completions.create( model="gpt-4o-mini", messages=messages, stream=True, stream_options={"include_usage": True}, ) -
Run one call and open the trace in the console. The span shows the resolved model, input and output token counts, and a cost. To see the call nested inside your agent’s run instead of as a standalone trace, wrap the surrounding function in
observe.
The OpenAI integration page has the full recipe for both languages.
What you get
- Every OpenAI chat completion in your process traced, with model, tokens, messages and a cost, from one
init()call. - Failed calls visible as ERROR spans that name the error class.
- Python streams with time to first token already recorded.
- Token and cost totals that count each call once when a framework wraps OpenAI.
- Nested traces when you add
observearound your own functions, so the OpenAI call appears inside the agent run it belongs to.
Manual spans add what the integration does not record. Use a manual generation (start_as_current_generation in Python, startAsCurrentGeneration in TypeScript) when you need time to first token on a TypeScript stream, when you compute usage yourself and pass it to set_usage() (setUsage()), or when a call is still counted twice and you want a single span. If a manual generation replaces an auto-instrumented call, turn that integration off first. Otherwise the generation and the integration’s span both carry the usage and the call is counted twice. In Python, rius.init(instruments=[]) turns all integrations off, and a list such as instruments=["openai"] keeps only the ones you name. TypeScript has no per-integration option.
OpenAI is one of several supported libraries and frameworks. The Integrations page has the support matrix.
When something else fits
- If you call a provider’s own HTTP API, or any provider with no integration, trace those calls as manual generations instead.
- If time to first token matters on TypeScript OpenAI streams, trace the streamed call as a manual generation, because the Node instrumentation does not record it.
- If you work in a language other than Python or TypeScript, send OpenTelemetry GenAI traces to Rius with a standard OpenTelemetry SDK instead of the Rius SDK.