UserBotLatencyObserver measures the time between when a user stops speaking and when the bot starts responding, emitting events for custom handling and optional OpenTelemetry tracing integration. It also tracks first-bot-speech latency and provides detailed latency breakdowns when metrics are enabled, including per-service metrics and contributions that name every part of the interval.
Features
- Tracks user speech start/stop timing using VAD frames
- Measures bot response latency from the actual moment the user stopped speaking
- Measures first bot speech latency (client connection to first speech)
- Provides detailed latency breakdown with per-service TTFB, text aggregation, user turn duration, and function call metrics
- Provides contributions timeline that names every part of the user-to-bot interval, including time no service measures
- Emits
on_latency_measuredevents for custom processing - Emits
on_latency_breakdownevents with detailed per-service metrics - Emits
on_first_bot_speech_latencyevent for greeting latency measurement - Automatically records latency as OpenTelemetry span attributes when tracing is enabled
- Automatically resets between conversation turns
Usage
Basic Latency Monitoring
Add latency monitoring to your pipeline and handle the event:Detailed Latency Breakdown
Enable metrics to collect per-service latency breakdown:OpenTelemetry Integration
When tracing is enabled, latency measurements are automatically recorded asturn.user_bot_latency_seconds attributes on OpenTelemetry turn spans. No additional configuration is needed.
How It Works
The observer tracks conversation flow through these key events:- Client connects (
ClientConnectedFrame) → Records timestamp for first-bot-speech measurement - User starts speaking (
VADUserStartedSpeakingFrame) → Resets latency tracking - User stops speaking (
VADUserStoppedSpeakingFrame) → Records timestamp, accounting for VADstop_secsdelay - Bot starts speaking (
BotStartedSpeakingFrame) → Calculates latency and emitson_latency_measuredandon_latency_breakdownevents
enable_metrics=True in PipelineParams, the observer also collects per-service metrics (TTFB, text aggregation, function call latency) from MetricsFrame instances and builds a contributions timeline that names every part of the user-to-bot interval, including the parts no service measures (VAD silence, turn detection, turn-completion markers).
Event Handlers
on_latency_measured
Called each time a user-to-bot latency measurement is captured.on_latency_breakdown
Called alongsideon_latency_measured with detailed per-service metrics collected during the user→bot cycle. The breakdown includes TTFB from each service, text aggregation latency, user turn duration, and function call timings.
LatencyContribution fields:
Each contribution names one part of the user-to-bot interval:
Methods:
turn_contribution_lines(by_cost=False)— Format contributions for logging, one per line plus a total. Passby_cost=Trueto order by duration rather than chronologically.chronological_events()— Deprecated since 1.9.0. Useturn_contribution_lines()instead, which names every part of the interval. Will be removed in 2.0.0.
on_first_bot_speech_latency
Called once when the bot first speaks after client connection. If the user starts speaking before the bot’s first speech, it is not called. Measures the time fromClientConnectedFrame to the first BotStartedSpeakingFrame. This is particularly useful for measuring greeting latency.
The
on_latency_breakdown event is also emitted for the first bot speech,
allowing you to see the detailed breakdown of what contributed to the greeting
latency.Configuration
Constructor Parameters
int | None
default:"None"
deprecated
Deprecated since 1.12.0, removed in 2.0.0. No replacement. The observer
receives each frame once.
float
default:"0.005"
Contributions shorter than this are rolled into the single pipeline entry
rather than listed separately. Pass
0 to list every contribution, including
individual frame hops.Callable[[], float]
default:"time.time"
Reads the current time in seconds. Supplying one lets a test drive a cycle
without waiting out the intervals it describes.
Limitations
- Requires proper frame sequencing to work accurately
- Per-service metrics are only collected when
enable_metrics=TrueinPipelineParams