What is P95 and P99 latency? How to measure it

Rene, Kabir Goel 
What is P95 and P99 latency? How to measure it

P99 latency is the response time that 99% of requests beat. If an API’s P99 is 400 milliseconds, 99 requests in a hundred come back in 400 ms or less and one takes longer. P95 is the same idea at 95%: one request in twenty is slower. Both describe the tail of the distribution, the slow requests that an average smooths away.

The tail matters more than its size suggests. A user who makes one request rarely notices it. A caller who talks to a voice agent for twenty turns probably will. This guide covers how percentiles work, how to compute them, the mistakes that make them lie, and what they mean for real-time voice AI.

P50, P95 and P99 at a glance

PercentileWhat it tells youRequests slower than it
P50The median, a typical request1 in 2
P90The start of the slow tail1 in 10
P95The usual target for dashboards and SLOs1 in 20
P99Rare slowdowns: pauses, retries, queueing1 in 100
P99.9Outliers that only show up at high volume1 in 1,000

Higher percentiles need more samples to mean anything. A P99 from 100 requests rests on a single request. Aim for at least a few hundred samples for P95 and a few thousand for P99, and print the sample count next to the number.

Why the average hides the tail

Take 100 requests. 94 finish in 200 ms and 6 take two seconds. The mean is 308 ms, which no request actually took. The median is 200 ms, which looks great. P95 and P99 are both 2,000 ms, which is what six of your users saw.

Real latency distributions are lopsided like this. Most requests take the fast path, and a minority wait behind a slow disk, a cold cache, a garbage collection pause or a full queue. An average blends the two groups into a number that describes neither. A median ignores the slow group entirely. Percentiles keep it visible.

How to calculate P95 and P99

Sort the measurements from fastest to slowest and read the value 95% or 99% of the way along. With 200 samples, P95 is the 190th value and P99 is the 198th. That’s the nearest-rank method:

import math


def percentile(samples, p):
    """Nearest rank: the smallest sample with at least p% of samples at or below it."""
    ordered = sorted(samples)
    rank = math.ceil(p / 100 * len(ordered))
    return ordered[max(rank, 1) - 1]


latencies_ms = [200] * 94 + [2000] * 6
print(percentile(latencies_ms, 50))  # 200
print(percentile(latencies_ms, 95))  # 2000
print(percentile(latencies_ms, 99))  # 2000

NumPy interpolates by default, so numpy.percentile can return a value between two samples. Pass method="inverted_cdf" to get nearest rank. On small samples the two methods can differ noticeably, which is one more reason to report the sample count.

Monitoring systems usually don’t keep every sample. They count requests into latency buckets and estimate the percentile from the histogram, as Prometheus’ histogram_quantile() does. The estimate is only as precise as the buckets around it, so put bucket boundaries near the latencies you care about.

Three mistakes that make percentiles lie

Averaging percentiles. Say one server handles 900 requests, all in 200 ms, and a second handles 100, ten of which take a full second. The P95s are 200 ms and 1,000 ms, and their average is 600 ms. The real P95 across all 1,000 requests is 200 ms. Prometheus’ documentation says the same: quantiles computed separately can’t be aggregated. Merge the histograms or raw samples, then compute.

Adding stage percentiles. A voice agent runs speech recognition, a language model and text to speech in sequence. Suppose recognition always takes 300 ms, the LLM takes 500 ms but 1,500 ms on one call in ten, and TTS takes 150 ms but 600 ms on one call in ten. Adding the stage P95s gives 2,400 ms. The actual P95 of the whole turn is 1,950 ms, because the two slow cases rarely land on the same turn. Measure the end-to-end time directly instead of estimating it from parts.

Measuring with a client that waits. A load generator that sends the next request only after the last one returns sends fewer requests exactly when the server is slow, so the slow periods are undercounted. Gil Tene calls this coordinated omission, and his load generator wrk2 exists to avoid it by sending at a fixed rate. For production numbers, measure real traffic rather than a test client.

Why the tail decides how a voice agent feels

Conversation runs on tight timing. A review of turn-taking research by Levinson and Torreira finds that gaps between turns are on the order of 200 ms. In a study of telephone calls, Kendrick and Torreira found that responses after gaps longer than about 700 ms were mostly refusals and other dispreferred answers, and that even gaps over about 300 ms made a plain acceptance less likely. Listeners read a pause as meaning something, so to a caller an agent that pauses for 900 ms can sound reluctant, not just slow.

Now multiply by turns. If each turn independently has a 5% chance of being slower than P95, a 20-turn call has a 64% chance of hitting at least one of them (1 − 0.95²⁰). Even the P99 shows up on about 18% of 20-turn calls. The median describes a typical turn; the tail describes a typical call. Google’s Jeff Dean and Luiz André Barroso made the same point about large services in The Tail at Scale: when one user action fans out into many requests, rare slow responses become common.

What to measure in a voice pipeline

Measure what the caller hears. For a voice agent, that’s the time from the end of the caller’s speech to the first audible sample of the reply, recorded on the caller’s side of the line. Then break it into stages so you know where the tail comes from:

StageWhat to timeCommon tail causes
Turn detectionEnd of speech to the turn being declared overHesitations, background noise, long pauses
Speech to textTurn end to final transcriptLong turns, network jitter
LLM and toolsTranscript to first token, including tool callsSlow tools, long prompts, provider queueing
Text to speechFirst text sent to first audible audioNew connections, long first sentences
Network and phoneAudio leaving your server to reaching the callerCarrier routing, jitter buffers

Time to first audio (TTFA) is the TTS number to watch, because a streaming model starts playback before the whole sentence is ready. Leading silence counts too: a chunk that starts with 300 ms of silence is 300 ms more waiting for the caller. The script below times the first bytes, so check your audio for leading silence separately.

Here’s a script that measures TTFA percentiles for Cartesia’s Sonic text to speech. It schedules 205 requests half a second apart, discards the first five, and times each from its scheduled start to the first audio bytes. Timing from the schedule rather than from when the request went out means a slow response that delays the next request shows up in the numbers, which avoids the coordinated omission described above:

import math
import os
import time

from cartesia import Cartesia


def percentile(samples, p):
    """Nearest rank: the smallest sample with at least p% of samples at or below it."""
    ordered = sorted(samples)
    rank = math.ceil(p / 100 * len(ordered))
    return ordered[max(rank, 1) - 1]


# max_retries=0: a retried request would hide a failure inside a slow sample.
client = Cartesia(api_key=os.environ["CARTESIA_API_KEY"], max_retries=0)
interval = 0.5  # seconds between scheduled requests
ttfa_ms = []
failures = 0
first = time.perf_counter() + interval

for i in range(205):
    # Each request has a fixed start time. If a slow response makes us late,
    # the wait counts against latency instead of quietly thinning the sample.
    scheduled = first + i * interval
    time.sleep(max(0.0, scheduled - time.perf_counter()))
    got_audio = False
    try:
        with client.tts.with_streaming_response.generate(
            model_id="sonic-3.6",
            transcript="Your order shipped this morning and should arrive on Thursday.",
            voice="6ccbfb76-1fc6-48f7-b71d-91ac6298247b",
            output_format={"container": "raw", "encoding": "pcm_s16le", "sample_rate": 16000},
            language="en",
        ) as response:
            for chunk in response.iter_bytes():
                if chunk:
                    got_audio = True
                    if i >= 5:  # the first requests pay for connection setup
                        ttfa_ms.append((time.perf_counter() - scheduled) * 1000)
                    break
    except Exception:
        pass
    if not got_audio:
        failures += 1

print(f"{len(ttfa_ms)} timed requests, {failures} failed or returned no audio")
if ttfa_ms:
    for p in (50, 90, 95, 99):
        print(f"p{p}: {percentile(ttfa_ms, p):.0f} ms")
    print(f"max: {max(ttfa_ms):.0f} ms")

Install the SDK with pip install cartesia and set CARTESIA_API_KEY from the dashboard. Run it from the region your servers run in, at the time of day your traffic peaks, because a laptop on home Wi-Fi measures the Wi-Fi. The SDK retries failed requests twice by default, which would fold a failure and its retry into one slow-looking sample, so the script turns retries off and counts failures, including responses with no audio, separately. Don’t leave them out of the report: a request that never answered is the worst latency of all. For a live agent, time the WebSocket path you actually ship, since it keeps one connection open across turns.

What public benchmarks show

Coval runs independent text to speech, speech to text and speech-to-speech benchmarks against public APIs every 30 minutes and publishes medians, percentiles and sample counts. Its methodology counts leading silence in TTFA and excludes connection handshakes.

On its 30-day text to speech board, read on October 15, 2026, the gap between median and P95 varied widely across 33 models with at least 260 samples each. For the typical model, P95 was 1.38 times the median. At the extremes, one model’s P95 was 1.1 times its median, and another’s was more than seven times its median: 624 ms typical, 4,751 ms for one request in twenty.

The lesson is the one from the start of this guide: two models with similar medians can feel very different on a call. Compare P95s, with sample counts, measured the way your users experience them.

Lowering tail latency

  • Keep connections open. A new HTTPS request pays for TCP and TLS setup again, and Cartesia’s docs note that this overhead is often on the same order as the time to the first audio byte itself. A WebSocket that stays open for the call pays it once.
  • Cache what repeats. Greetings, hold messages and sign-offs don’t need a fresh generation on every call. Cache them as raw audio and splice them into the live stream.
  • Start speaking sooner. Stream LLM tokens into text to speech as they arrive instead of waiting for a whole paragraph.
  • Put a deadline on tools. A tool call that takes two seconds adds two seconds to the turn, every time. Set a timeout, and have the agent say what it’s doing while it waits.
  • Hedge the slow requests. The Tail at Scale describes sending a backup request once the first has been outstanding longer than the usual P95, and using whichever answers first. Waiting until P95 limits the extra load to about 5%. Only hedge requests that are safe to send twice, like generating the same audio again, never a tool call that writes.
  • Run the models close to the call. If network distance or shared infrastructure is your tail, on-premise deployment puts the models next to your telephony.

If you’d rather not assemble and tune the pipeline yourself, Cartesia Managed Agents run turn detection, Ink speech to text, the LLM and Sonic on a phone number, and you can build one in the playground and call it. If your own pipeline is slow, the fix is usually in whichever stage your measurements point to, and the script above is the place to start.

FAQs

What is P99 latency?

P99 latency is the 99th percentile of response times: 99% of requests finish at or below it, and the slowest 1% take longer. If an API's P99 is 400 ms, one request in a hundred takes more than 400 ms. It describes the slow end of the distribution, which an average hides.

What is P95 latency?

P95 latency is the response time that 95% of requests meet or beat. One request in twenty is slower. It's the percentile most teams put on dashboards and in service-level objectives, because it moves with real problems but isn't dominated by a handful of freak events.

What is the difference between P95 and P99?

P95 is the slowest 5% of requests; P99 is the slowest 1%. P95 tracks how the system behaves under normal load. P99 tends to be set by discrete events such as garbage collection pauses, cold caches, retries and queueing. Report both, with the median, and say how many samples they came from.

What is tail latency?

Tail latency is the slow end of a latency distribution, usually everything from P95 upward. The name comes from the long right-hand tail of the histogram. In systems that make many requests per user action, or many turns per conversation, the tail is what most users eventually hit.

Can you average P95 values?

No. A percentile of a combined set of requests isn't the average of each part's percentile, and the P95 of a pipeline isn't the sum of each stage's P95. Keep raw samples or histograms, merge those, and compute the percentile from the merged data.

What P95 latency does a voice agent need?

Measure from the moment the caller stops speaking to the first audio they hear. In conversation research, people hand the floor to each other in about 200 ms, gaps over about 300 ms make a plain yes less likely, and gaps over about 700 ms are associated with refusals and other dispreferred answers. A voice agent whose P95 response sits near a second sounds hesitant on one turn in twenty.