On this page
OpenTelemetry for voice agents, explained plainly
What a call trace is, how OpenTelemetry records one, and how to use traces when you test a voice agent.
By Greg East, 7 minute read. Sources checked .
OpenTelemetry for voice agents means recording each call as a timed trace. The trace splits the call into steps such as listening, thinking, using a tool and speaking, and shows how long each one took and what it handled. OpenTelemetry is an open source standard, so the same trace can be opened in many different tools. When a caller says "it just sat there", the trace shows which step was slow, and when the agent says the wrong thing, it shows whether the fault was in hearing, thinking or speaking.
Key facts
- OpenTelemetry is, in its own words, "Open source, as well as vendor- and tool-agnostic".
- OpenTelemetry defines a span as "a unit of work or operation", and a trace is built from spans (OpenTelemetry traces).
- Pipecat tracing is off by default and switched on with
enable_tracing(Pipecat docs). - LiveKit Agents produces OpenTelemetry traces for every session, which any OTLP backend can receive (LiveKit tracing).
- The GenAI inference conventions are marked "Development", so field names can still change (OpenTelemetry GenAI conventions).
What are a trace and a span?
A trace is the full route one request takes through a system, from start to finish. OpenTelemetry's own page defines a span as "a unit of work or operation", and a trace is built from spans. Each span has a name, a start time and an end time. A span can sit inside another one, so a trace reads as a tree.
For a voice agent, think of one phone call as one trace. Inside it is a span for each turn, and inside each turn are the steps that produced the reply. Those are speech recognition, the language model, any tool the agent called, and speech synthesis. Because every span is timed, you can see where the seconds went.
Why does a timed trace help when you debug a voice agent?
A transcript tells you what was said. It does not tell you why a pause was long or why a number came out wrong. A trace gives you the middle of the story.
Take a pause of several seconds before the agent replied. It might have come from a late decision that the caller had finished speaking, a slow transcript, a slow first word from the model, a slow tool or slow speech synthesis. LiveKit's metrics page lists a separate figure for several of those stages, such as the delay before a turn is judged complete, the time until the model starts to answer and the time until the first audio is ready. Without them the fault is just "slow". With them you know which supplier or setting to look at.
The same goes for wrong answers. If the transcript step recorded the wrong word, the model was never at fault. If the transcript was right but the tool call carried the wrong value, the fault sits later. Pipecat records tool activity as its own spans, so you can see what the tool was given and tell the two cases apart.
What is the standard behind it?
OpenTelemetry is, in its own words, "Open source, as well as vendor- and tool-agnostic". It is part of the Cloud Native Computing Foundation. It defines how traces are produced and sent, but it is not a place to view them. You send the traces to a separate tool of your choice.
For AI systems there is an add-on called the GenAI semantic conventions. These are agreed names for the details of a model call, such as which model ran and how many tokens it used. They are not final. The inference page is marked "Development", which means the names can still change. The conventions have also moved to their own repository, so the old page on the OpenTelemetry site is no longer kept up to date.
Voice is the least settled part. A proposal for live, two-way sessions such as OpenAI Realtime and Gemini Live was still an open proposal on GitHub (a pull request) when we read it. Its author argues that realtime sessions do not have a single request and response boundary, which is exactly what makes a phone call awkward to describe. In practice this means that speech-specific details are recorded under each framework's own names today, such as turn.was_interrupted in Pipecat and the lk.* names in LiveKit.
Which voice frameworks emit traces?
Two popular open source frameworks do. For setup and testing detail, see our guides to testing a Pipecat agent and testing a LiveKit agent.
Pipecat. Its tracing page says to switch on enable_tracing, which is off by default. The trace then has a conversation span at the top, a span for each turn under it, and separate spans for speech recognition, the model and speech synthesis inside each turn. Turn spans carry a flag, turn.was_interrupted, that records whether the caller cut in. Realtime models such as Gemini Live and OpenAI Realtime get a different layout.
LiveKit Agents. Its tracing page says every session produces OpenTelemetry traces, which you can send to any backend that accepts the OTLP format. It uses two sets of attribute names. The lk.* names hold LiveKit's own data, such as speech IDs and turn timings. The gen_ai.* names follow the OpenTelemetry GenAI conventions.
Both can include the words spoken. That is personal data in many calls. LiveKit labels the content attributes with a lk.pii. prefix and lets you withhold them from your own tracing tool with allow_pii=False. Its page notes that LiveKit's software removes whole attributes and does not mask values, and that LiveKit Cloud still receives the full data. Decide what your traces may hold before real callers appear in them.
Hosted platforms such as Vapi and Retell have their own call logs. We have not covered how those export traces here, so check their documentation, or compare them in Vapi vs Retell vs Bland.
How do you use call traces when testing a voice agent?
Text-only tests are the cheap first pass. LiveKit's guidance is that text mode is "a cost-efficient and deterministic way to test agent behavior" and that audio runs should be reserved for turn-taking and speech-specific issues. Those audio runs are where traces earn their keep, since text has no speech recogniser, no synthesis and no waiting to measure.
A routine that works:
- Give every test call an ID you control. Pass it to the agent so it appears on the trace. Cekura's Pipecat integration joins traces to its call logs this way, using a session ID.
- Store the trace beside the recording and the result. When a test fails, you want the audio, the transcript and the timed steps open together. RingTru's evidence report groups failed calls by cause, each with the lines that prove it.
- Read the turn timings first. Look for the turn where the pause was longest, then open its steps. Compare that turn with the others in the same call. One slow tool call is a different problem from slowness everywhere.
- Check the value at each step. For a name, a date or a reference number, find what was heard, what went into the tool and what was read back. The first place they differ is where the fault is.
- Check interruptions. Look at which turns were flagged as interrupted and whether the agent stopped when it should have. The interruption guide lists what to try.
- Repeat on the same script. Run one scenario many times, and compare the spread of timings, not a single run. See turn-taking and latency.
What can go wrong?
- Renamed fields. LiveKit's page says that attribute and log field renames between versions mean old queries and dashboards return no matches and raise no error, so a dashboard that uses an old name simply shows nothing. Re-check your queries after an upgrade.
- Standards drift. Because the GenAI names are still in development, keep your own field names in one mapping file so you can swap them later.
Everything above was checked against the linked pages on 27 October 2026. Related: how to test a voice agent, and the glossary.