To trace LiveKit Agents with Braintrust’s TypeScript SDK, use auto-instrumentation, manual instrumentation, or OpenTelemetry. Auto-instrumentation and manual instrumentation trace sessions that use a STT-LLM-TTS pipeline, and require Braintrust v3.39.0 or later and After a call ends, its trace appears on the Logs page of your project. The The auto-instrumentation example uses plain JavaScript so
Braintrust attaches the recording to the Without the package, recordings upload as raw PCM (
@livekit/agents v1.9.1 to v1.9.x. Audio recording requires Braintrust v3.41.0 or later.Auto-instrumentation
To trace LiveKit Agents without modifying your application code, run your agent with Braintrust’s import hook. Braintrust records LiveKit’s session, turn, and model activity directly through the Braintrust SDK, without requiring an OpenTelemetry pipeline. If your app also sets a LiveKit tracer provider that exports somewhere other than Braintrust, Braintrust leaves it in place.Setup
These steps add Braintrust to an existing LiveKit Agents app. They trace each session and record its audio.1
Install Braintrust
Add
braintrust and @braintrust/audio to your agent’s project. We strongly recommend using @braintrust/audio to compress recordings and reduce upload size.2
Set your environment variables
Add your Braintrust API key and the two audio recording flags to your agent’s
.env file. BRAINTRUST_CAPTURE_USER_AUDIO_ATTACHMENTS and BRAINTRUST_CAPTURE_AGENT_AUDIO_ATTACHMENTS turn on audio recording for the caller and the agent. Without them, traces include spans and metadata but no audio..env
3
Initialize a logger and run your agent with the import hook
Initialize a Braintrust logger in your agent’s entry file, and flush it in a shutdown callback in your agent’s Then run the agent with Braintrust’s import hook.
entry function. When a job ends, LiveKit Agents closes the session, which waits for the recording to finish uploading, and then exits the job process. Without the flush, the session’s last spans can be lost when the process exits.--env-file loads your .env file and requires Node.js 20.6.0 or later. LiveKit runs each job in a child process that inherits these flags, so the hook also applies to your sessions.session root span holds the call recording, with turn, model, and speech spans nested under it. See What Braintrust traces for the full list.Example agent
This minimal pipeline agent uses separate speech-to-text, LLM, and text-to-speech models and is traced with the setup above. It uses the@livekit/agents-plugin-openai plugin and the LiveKit and OpenAI credentials from your .env file.livekit_agent.js
node --import can run the file directly. The Braintrust APIs work the same in TypeScript projects. Compile your TypeScript to JavaScript and run the compiled file with the import hook, or run TypeScript directly with a TypeScript loader.If you’re using a bundler, see Trace LLM calls for plugin and loader setup.
Set up manually
Set up manually
To trace LiveKit without the import hook, wrap the Register the same shutdown callback as in Setup so the session’s last spans are sent before the job process exits.
@livekit/agents module with wrapLiveKit() before you create sessions. Sessions created through the wrapped module’s voice.AgentSession are fully traced, including speech-to-text spans, and call audio when audio recording is on.TypeScript
Opt out of LiveKit Agents tracing
Opt out of LiveKit Agents tracing
If you use auto-instrumentation for other libraries but want to exclude LiveKit Agents, add
livekit to the BRAINTRUST_DISABLE_INSTRUMENTATION environment variable. This also disables wrapLiveKit().What Braintrust traces
Auto-instrumentation andwrapLiveKit() produce the same spans:- Session spans (
session), the root span covering the full agent session. - User turn spans (
user_turn), with child user speech spans (user_speech) that hold the transcript, and speech-to-text spans (stt) with the final transcript, model, provider, confidence, and language. - Agent turn spans (
agent_turn), covering the agent’s reply. - LLM spans (
llm_response), with the chat context as input, the assistant’s reply and tool calls as output, model and provider, the function tools and tool choice available to the reply intoolsandtool_choicemetadata, token usage, and time to first token. - Tool spans named after each function tool, with tool arguments and output.
- Text-to-speech spans (
tts). - Agent speech spans (
agent_speech), with the text the user heard and whether the user interrupted it. - LiveKit lifecycle spans (
livekit.<name>), such aslivekit.session_start,livekit.on_enter,livekit.eou_wait,livekit.llm_request_run, andlivekit.tts_request, with LiveKit’s original nesting and attributes. Requires v3.40.0 or later.
metadata, with lk.* keys renamed to contrib.livekit.*. LLM and text-to-speech calls that LiveKit makes inside a traced session are recorded in the llm_response and tts spans, not as separate provider spans such as OpenAI spans.Audio attachments
Audio recording is off by default and requires Braintrust v3.41.0 or later. Each side of the call has its own environment variable, which takes1 or true:BRAINTRUST_CAPTURE_USER_AUDIO_ATTACHMENTSrecords the caller’s audio that the session receives.BRAINTRUST_CAPTURE_AGENT_AUDIO_ATTACHMENTSrecords the agent’s audio that played.
In v3.41.0 and later,
BRAINTRUST_CAPTURE_ATTACHMENTS no longer records LiveKit Agents audio. If you used it to record calls, set the two variables above instead.session span. See Configure recording encoding to change how recordings are encoded.Braintrust records 24 kHz, two-channel audio, with the caller on the first channel and the agent on the second. If you record only one side, the other channel is silent.session.close() resolves only after the recording finishes uploading. LiveKit Agents closes the session when the job ends, before it exits the job process. If you close the session yourself, await session.close(). To send the session’s last spans before the process exits, call logger.flush() in a shutdown callback, as shown in Setup.Configure recording encoding
The@braintrust/audio package compresses recordings to Opus audio in Ogg files. It requires Node.js 20 or later. Braintrust finds and loads the package from node_modules automatically, so you don’t import it in your code. The default settings work without any configureInstrumentation() call.If you deploy a bundle without node_modules, import the package in your app so your bundler includes it:audio/pcm, 16-bit little-endian interleaved samples, without a WAV header). Recordings also fall back to raw PCM, with a warning, when the package fails to load, doesn’t match your braintrust version, or the audio options contain an unsupported value.The encoding settings are optional tuning. To change them, pass audio options for the livekit integration to configureInstrumentation(), in the same separate file that you load before the hook:configure.mjs
Braintrust splits the recording into attachments that each hold about 4 MiB of raw PCM, about 44 seconds of audio. Compressed attachments cover the same duration in fewer bytes. To change the size, set
streamingAttachmentBufferBytes with configureInstrumentation() from braintrust/instrumentation. Call it in a separate file, and load that file before the hook. A call from a file that imports braintrust has no effect.configure.mjs
Tracing resources
- LiveKit Agents overview: LiveKit Agents documentation
- Braintrust package on npm
@braintrust/audiopackage on npm
OpenTelemetry
Braintrust attaches to LiveKit’s built-in OpenTelemetry pipeline by registering a span processor with LiveKit’s tracer provider.Setup
1
Install dependencies
@livekit/agents is built against OpenTelemetry JS 1.x. Keep every OpenTelemetry package on its 1.x-compatible version, as pinned above. Upgrading any of them to 2.x breaks LiveKit at build or run time. The OTLP exporter packages use a separate 0.x version sequence that moves in step with the stable 1.x packages, so @opentelemetry/exporter-trace-otlp-http pins to ^0.57 rather than ^1.2
Set your environment variables
.env
Configure tracing
Configure Braintrust’s span processor and set it as LiveKit’s tracer provider. KeepfilterAISpans set to false so LiveKit’s session, speech, and turn spans are included.livekit_agent.ts
What Braintrust traces
These spans come from LiveKit’s native OpenTelemetry instrumentation. With the OpenAI realtime model, the LLM, speech-to-text, and text-to-speech work happens inside a single realtime model call rather than as separate spans.- Session spans (
agent_session), the root span covering the full agent session - Agent turn spans (
agent_turn), with the model request, token usage, and realtime model metrics (gen_ai.*,lk.realtime_model_metrics) - User speaking spans (
user_speaking), with participant and speech detection details - Agent speaking spans (
agent_speaking), covering the agent’s spoken response - Activity lifecycle spans (
start_agent_activity,on_enter,on_exit,drain_agent_activity)
Tracing resources
- OpenTelemetry Integration: Braintrust’s OpenTelemetry support
- Trace application logic: Add custom spans and attributes to your traces
- LiveKit Agents overview: LiveKit Agents documentation