Claude API Latency Benchmark Testing Guide
If you're trying to figure out how fast the Claude API actually is for your workload, the short answer is: it depends on model, prompt length, output length, and whether you stream — and the only reliable way to know is to benchmark it yourself with your own prompts, not rely on published averages. This guide walks through exactly how to design and run a Claude API latency benchmark, which metrics matter, and how to interpret the results.
Generic latency numbers from blog posts or vendor pages are close to useless for capacity planning because they don't reflect your prompt size, your system prompt overhead, or your output token count. A proper benchmark measures your traffic pattern against the API you're actually going to ship with.
What "latency" actually means for an LLM API
Before writing any test code, separate latency into the components that matter:
- Time to first token (TTFT) — how long before the first byte of the response streams back. This is what determines perceived responsiveness in chat UIs.
- Total request latency — time from request sent to the final token received, including the full generation.
- Tokens per second (throughput) — generation speed once streaming starts, calculated as
(output_tokens - 1) / (total_time - ttft). - Network/connection overhead — DNS, TLS handshake, and queueing time before the model even starts processing.
Most teams only measure total request latency and miss that TTFT is usually the number that matters for interactive products, while total latency matters more for batch or agentic pipelines.
Designing a representative benchmark
A benchmark is only as good as its inputs. Build your test set around these variables:
- Prompt length — test short (under 200 tokens), medium (1-4k tokens), and long (full context, 50k+ tokens) inputs separately. Latency scales with input size, especially for cache-miss requests.
- Output length — cap
max_tokensat realistic values for your use case, not an arbitrary large number. A benchmark that always generates 4000 tokens will misrepresent a product that typically returns 150. - Model — Claude's model tiers differ meaningfully in speed. Always label results by model version.
- Streaming vs non-streaming — if your product streams, benchmark with streaming enabled since TTFT is only meaningful there.
- Concurrency — run single-request tests first, then ramp concurrency to see how latency degrades under load from your own infrastructure or rate limits.
Run each configuration at least 20-30 times. LLM latency has real variance — a single sample tells you almost nothing.
A simple benchmark script
Here's a minimal Node.js script that measures TTFT and total latency over streaming requests. It's written against a generic Claude-compatible endpoint; swap in your actual API base URL and auth header.
import { performance } from "node:perf_hooks";
async function benchmarkOnce(prompt, maxTokens) {
const start = performance.now();
let firstTokenTime = null;
let tokenCount = 0;
const res = await fetch("https://api.example.com/v1/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "claude-model-id",
max_tokens: maxTokens,
stream: true,
messages: [{ role: "user", content: prompt }],
}),
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
if (firstTokenTime === null) firstTokenTime = performance.now();
tokenCount += decoder.decode(value).split("\n").length;
}
const end = performance.now();
return {
ttft_ms: firstTokenTime - start,
total_ms: end - start,
};
}
async function runBenchmark(prompt, maxTokens, iterations = 30) {
const results = [];
for (let i = 0; i < iterations; i++) {
results.push(await benchmarkOnce(prompt, maxTokens));
}
return results;
}
From the raw results, compute p50, p90, and p99 for both ttft_ms and total_ms — averages hide tail latency, and tail latency is what causes timeout complaints in production.
Measuring with curl for quick spot checks
For fast manual checks without writing a script, curl with -w gives you basic timing:
curl -s -o /dev/null -w "DNS: %{time_namelookup}s Connect: %{time_connect}s TTFB: %{time_starttransfer}s Total: %{time_total}s\n" \
-X POST https://api.example.com/v1/messages \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"claude-model-id","max_tokens":256,"messages":[{"role":"user","content":"Hello"}]}'
This won't give you true TTFT for streaming (curl's time_starttransfer measures first byte of the HTTP response, not first generated token), but it's a fast way to catch network-level regressions like a bad region or DNS issue before running a full benchmark.
Common mistakes that skew results
- Testing from a distant region. If your servers are in Europe and you benchmark from a laptop in another continent, you're measuring network distance, not model latency.
- Ignoring cold starts. The first request after a connection pool is idle is often slower. Warm up with a few discarded requests before recording.
- Comparing streaming to non-streaming total time. Total latency is roughly similar either way, but non-streaming has no TTFT to report — don't average the two together.
- Not controlling for prompt caching. If your requests reuse a long system prompt or context, caching can dramatically cut latency on repeat calls. Benchmark cache-hit and cache-miss scenarios separately if you rely on caching.
- Single-run testing. One fast request and one slow request are both noise. You need distributions, not anecdotes.
Where an API layer affects latency
If you're accessing Claude through a gateway or proxy layer rather than talking to Anthropic directly, that layer adds its own hop — so it's worth benchmarking the exact path your production traffic takes, not an idealized direct connection. SubToAPI exposes Claude access as a standard HTTPS API with streaming support, so you can run the same TTFT and total-latency tests shown above directly against https://api.subtoapi.app/v1/messages and compare the numbers against your current setup. Check the streaming docs and messages docs for request shape details, or start from the quickstart if you're setting up a benchmark environment for the first time.
Turning benchmark results into decisions
Once you have p50/p90/p99 numbers for TTFT and total latency across your real prompt shapes, use them to:
- Set realistic client-side timeouts (generally p99 + margin, not p50).
- Decide whether to stream based on measured TTFT improvement for your prompt sizes.
- Pick the right model tier — faster models often have a quality tradeoff that's only worth it if your p90 latency target actually requires it.
- Catch regressions by re-running the same benchmark suite after any infrastructure or model version change.
Questions
Does Claude API latency vary by model? Yes, significantly. Faster, smaller models typically have lower TTFT and higher throughput than larger, more capable models. Always benchmark per-model and compare against your actual quality requirements.
Should I measure latency with streaming or non-streaming requests? Measure both if your product uses both, but treat them as separate metrics. Streaming gives you TTFT, which matters for perceived responsiveness; non-streaming only gives total latency, which matters for batch jobs.
How many requests do I need for a reliable benchmark? At least 20-30 per configuration (prompt length, output length, model, concurrency level). LLM latency has real variance, so single-sample or small-sample tests will give misleading percentile estimates.