Session Observability
Log client and server WebSocket messages for per-session, turn-by-turn observability into transcripts, agent behavior, function calls, errors, and latency.
The Voice Agent dashboard surfaces high-level usage, but it does not give you per-session, turn-by-turn observability. Everything you need is already flowing across the WebSocket. This guide explains what to capture and how to structure it so you get full observability into transcripts, agent behavior, function calls, errors, and latency.
The Core Idea
The Agent API runs over a single WebSocket connection (wss://agent.deepgram.com/v1/agent/converse). All control and event traffic moves across that socket as JSON messages in both directions. There is no separate logging API, so the recommended pattern is to tap the WebSocket and persist every non-audio frame, in both directions, keyed to the connection’s request_id.
That gives you a complete, replayable record of each session that you can join back to the high-level usage in the dashboard.
What to Capture
Connection and Metadata
request_idfrom theWelcomemessage. This is the unique ID for the session and the key you use to correlate your logs with dashboard usage. The server sendsWelcomeas soon as the socket opens, so capture it first.- The full
Settingsmessage you send. This is your record of how the agent was configured: the listen / think / speak providers and models, the prompt, the functions,context_length, thetagsarray (tags also flow into usage records, so they become your filtering dimension), and flags such ashistory,experimental, andmip_opt_out. SettingsAppliedconfirmation from the server. See Settings Applied.
Server Events to Store
For a complete reference of all server events, see Outputs: Server Events.
Client Messages to Store
SettingsInjectUserMessage/InjectAgentMessage(injected text turns)UpdatePrompt/UpdateThink/UpdateSpeak/UpdateListen(mid-call configuration changes, so you can reconstruct agent state at any point in the call)FunctionCallResponse(function results returned to the agent)
For a complete reference of all client messages, see Inputs: Client Messages.
Skip the raw binary audio frames unless you specifically need call recordings. If you do, store them separately.
LatencyReport: Detailed Latency Telemetry
Set experimental: true at the top level of your Settings message and the server will emit a LatencyReport event. This is the richest latency signal available. Capture it the same way as every other frame.
It breaks latency down across the full STT → LLM → TTS pipeline. All fields are floats in seconds, and each is optional (omitted when not applicable to that turn):
This lets you attribute latency to the right stage — for example, separating LLM time-to-first-token from TTS time, and isolating tool-call and thinking overhead.
LatencyReport is gated behind experimental: true, so treat the schema as subject to change. Because the fields are optional, log defensively rather than assuming every field is present on every report.
Recommended Logging Shape
Wrap every captured frame in your own envelope. Most Agent messages do not carry their own timestamps, so stamp them yourself on send or receive.
request_id: from theWelcomemessage — the correlation key for joining your logs with dashboard usage.seq: a monotonic counter you assign for ordering.ts: wall-clock time when you sent or received the frame.direction:server_to_clientorclient_to_server.
Write these append-only, one record per frame (JSONL per session, or a table keyed on request_id + seq). From that store you can:
- Reconstruct the transcript by ordering
ConversationTextevents. - Chart latency from
LatencyReport. - Audit agent behavior via
AgentThinking, function calls, and mid-callUpdate*messages. - Alert on
Error/Warningrates.
Things to Keep in Mind
- Timestamps are yours to add. The protocol does not stamp messages, so record wall-clock time on send and receive, and assign a monotonic sequence number for ordering.
- Keep
flags.historyenabled if you wantHistoryevents. It is on by default. - Set
experimental: trueto receiveLatencyReport, and treat that schema as subject to change. - Set
mip_opt_outinSettingsif the data should not be used for model improvement.