Skip to main content

Sending Traces via OpenTelemetry

Checks and monitors tell you what happened: a conversation scored low, or a check failed. Traces tell you why. By sending OpenTelemetry traces to Okareo, you can see the inner workings of your system (every tool call, retrieval step, and LLM invocation) alongside the simulation transcript or monitored conversation that produced a given score. When a simulation run surfaces a behavioral issue or a monitor flags a production conversation, traces give you the full picture of what your system actually did under the hood.

You can send OpenTelemetry (OTEL) traces directly to Okareo instead of, or in addition to, routing traffic through the Okareo Proxy. This is useful when you already have OTEL instrumentation in your application or when the proxy approach doesn't fit your architecture.

Traces Endpoint

Send OTEL traces to:

POST https://api.okareo.com/v1/traces

Authenticate with your Okareo API key in the request headers.

The endpoint accepts the OTLP/proto (protobuf) format, which is the default for OpenTelemetry SDK exporters.

Headers

HeaderValue
api-keyYour Okareo API key
Content-Typeapplication/x-protobuf

Example

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

# Configure the OTEL exporter to send traces to Okareo
# The default exporter uses protobuf encoding (application/x-protobuf)
exporter = OTLPSpanExporter(
endpoint="https://api.okareo.com/v1/traces",
headers={"api-key": "<OKAREO_API_KEY>"},
)

provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)

tracer = trace.get_tracer("my-llm-app")

# Instrument your LLM calls
with tracer.start_as_current_span("chat_completion") as span:
span.set_attribute("llm.request.model", "gpt-4o")
# ... your LLM call here ...
span.set_attribute("llm.response.content", response_text)
note

Install the required packages:

pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
caution

The endpoint only accepts protobuf-encoded payloads (application/x-protobuf). JSON (application/json) is not supported and will return an Unsupported Content-Type error. Make sure you use the otlp-proto exporter variants, not otlp-http with JSON.

Supported Span Formats

Okareo natively understands traces from several popular standards and frameworks:

If your application already emits traces in any of these formats, Okareo will automatically extract the session or conversation identifier from the spans. No extra instrumentation is needed.

Linking Traces to Simulations via Context Token

When you define a Custom Endpoint Target with a session_id mapping, traces sent to Okareo are automatically associated with the corresponding simulation. In Okareo, this association key is called the Context Token. It links a trace span to a specific simulation conversation.

How it works

  1. Configure your Target with a response_session_id_path that extracts a session or thread ID from your API responses (see Custom Endpoint → Configure a Target).

  2. Run a simulation. Okareo uses the session_id from your Target as the Context Token and matches it against incoming traces.

  3. Traces are linked automatically. If your application emits gen_ai, LiteLLM, or A2A/ADK spans, Okareo extracts the session identifier from the standard span attributes and associates the traces with the simulation. No manual span tagging is required.

No extra instrumentation for standard formats

If you're using gen_ai semantic conventions, LiteLLM, or A2A/ADK, the session/conversation ID is already present in your spans. Okareo will find it and set the Context Token automatically.

If your traces use a custom format that doesn't follow one of the supported standards, you can manually include the session ID as a span attribute so Okareo can match it:

# Only needed for custom/non-standard trace formats
with tracer.start_as_current_span("handle_message") as span:
span.set_attribute("session.id", thread_id) # same ID your API returns
# ... process the message ...

Once linked, you can view the full trace timeline alongside the simulation transcript in the Okareo UI. This shows not just what the agent said, but the internal calls, latencies, and tool invocations that led to each response.

tip

This is especially valuable for multi-turn simulations where you want to verify that your agent's internal behavior (tool calls, retrieval steps, memory access) matches what it says in the conversation.

When to Use Direct Tracing vs. the Proxy

ApproachBest for
Okareo ProxyQuick setup, no existing OTEL instrumentation, want a unified gateway for multiple providers. See Setting Up Monitoring.
Direct OTEL TracesExisting OTEL instrumentation, need detailed internal spans (tool calls, retrieval, memory), or architectures where a proxy isn't feasible.
BothUse the proxy for LLM-level monitoring and direct traces for internal application observability. They complement each other.

Next Steps