A client-side timer that starts when the user presses a button and stops when audio plays back measures something real, but it is easy to accidentally measure the wrong interval — for example starting the clock before the network round trip even begins.
The number that predicts how a conversation feels
Endpoint-detected-to-first-audible-token, measured on the server where the endpointing decision and the synthesis start both actually happen.
# measures the interval that matters: silence detected -> first audio byte sent def measure_turn_latency(endpoint_ts: float) -> float: first_audio_ts = wait_for_first_tts_chunk() latency_ms = (first_audio_ts - endpoint_ts) * 1000 log_latency("turn_latency_ms", latency_ms) return latency_ms
Why this makes p50/p95 comparable
Logged this way, the p50 and p95 are directly comparable across sessions and languages, instead of each client computing its own slightly different definition of "latency". Arabic sessions carry a real endpointing penalty from longer pause tolerance — reporting that honestly is part of the measurement, not a caveat to hide.