Measure how long each phase of a request takes (DNS, connect, TLS, first byte, total) to pinpoint where latency comes from.
Measure how long each phase of a request takes (DNS, connect, TLS, first byte, total) to pinpoint where latency comes from.
curl -o /dev/null -s -w \
'dns: %{time_namelookup}s\nconnect: %{time_connect}s\ntls: %{time_appconnect}s\nttfb: %{time_starttransfer}s\ntotal: %{time_total}s\n' \
https://api.example.com/dataconst t0 = performance.now();
const res = await fetch('https://api.example.com/data');
const ttfb = performance.now();
await res.arrayBuffer();
const done = performance.now();
console.log(`ttfb ${(ttfb - t0).toFixed(1)}ms, total ${(done - t0).toFixed(1)}ms`);import requests
res = requests.get('https://api.example.com/data')
# elapsed = send -> last byte of headers received
print('elapsed:', res.elapsed.total_seconds(), 's')curl's `-w` (write-out) prints timing variables after the transfer. The key ones are `time_namelookup` (DNS), `time_connect` (TCP), `time_appconnect` (TLS handshake done), `time_starttransfer` (TTFB, first byte), and `time_total` (whole thing). Add `-o /dev/null -s` to discard the body and progress meter so you see only the numbers.
These variables are cumulative, so compute each phase by subtraction — e.g. pure TLS time = `time_appconnect - time_connect`. A high TTFB points to slow server processing, a high `namelookup` to DNS issues, and a high `connect` to network round-trip (RTT) latency.
In the browser use `performance.now()` or the Resource Timing API; in `requests` use `res.elapsed` (note it excludes body-download time). If the server sends a `Server-Timing` header you get a breakdown of its internal processing. For accurate benchmarks, repeat the measurement several times to reduce cache and keep-alive effects.