The fastest way to see how long an API call takes is curl -s -o /dev/null -w '%{time_total}\n' https://api.example.com/, which prints just the total time and nothing else. That single number won't tell you whether the delay is DNS, the network, TLS, or the server itself — for that you need to split the request into stages. This walks through five numbers instead of one, and what to do with each.
1. How long did that request actually take?
$ clai how many seconds does this address take to respond→ curl -s -o /dev/null -w '%{time_total}\n' https://cliai.tech/1.244094
-o /dev/null throws away the response body, -s hides the progress meter, and -w prints only what you asked for. There's a number now, but it explains nothing.
2. Break the time down by stage
$ clai break down the response time by stage: dns, connect, tls, first byte→ curl -s -o /dev/null -w 'dns: %{time_namelookup}\nconnect: %{time_connect}\ntls: %{time_appconnect}\nttfb: %{time_starttransfer}\ntotal: %{time_total}\n' https://cliai.tech/dns: 0.000782connect: 0.299098tls: 0.414729ttfb: 1.124750total: 1.244094
The values are cumulative, not independent — what matters is the gaps between them. DNS took 0.0008s, setting up the TCP connection took 0.298s, the TLS handshake took 0.116s, and from TLS-ready to first byte took 0.71s — that's the server thinking. That's where the problem lives, if there is one.
3. Read the differences, not the raw numbers
time_namelookup above 0.1s points at the resolver or a cold cache. connect - namelookup is the network latency to the server, roughly half the round-trip ping. starttransfer - appconnect is how long the server spent thinking about the request. total - starttransfer is body transfer time, and it scales with the response size.
4. Is it even a 200?
$ clai show the time, status code, and body size→ curl -s -o /dev/null -w 'code: %{http_code} size: %{size_download} total: %{time_total}\n' https://cliai.tech/code: 200
A timing number without the status code is worthless — a fast 500 doesn't mean everything's fine. The full variable list lives in man curl, under WRITE-OUT VARIABLES.
5. One measurement is not enough
$ clai measure the response time five times in a row→ for i in $(seq 5); do curl -s -o /dev/null -w '%{time_total}\n' https://cliai.tech/; done
A single measurement means nothing. The first request is almost always slower because of cold DNS and connection setup. Look at the spread across runs, not the first number.
6. Move the format into a file
$ clai save the timing format to a file and reuse it→ curl -s -o /dev/null -w @curl-format.txt https://cliai.tech/
-w @file reads the format from a file, so the long inline string stops getting in the way. Teams usually keep that file in the repo next to their other check scripts.
Gotchas
- The values are cumulative.
time_appconnectalready includes DNS and the connection. Subtract the previous stage, or you'll conclude TLS took half a second when that's really the sum of everything before it. time_appconnectis zero for plain HTTP. There's no TLS stage without TLS, and zero here isn't a measurement error.- curl measures one request, not performance. For load, use
hey,wrk, ork6. curl answers "where is the time going," not "how much traffic can this take."
Related questions
What is TTFB? Time to first byte — the time_starttransfer value in the output. It's usually the clearest signal of backend speed.
Why is the first request always slower? Cold DNS cache, TCP setup, and the TLS handshake. A repeated request over keep-alive skips all three.
How do I measure just DNS? %{time_namelookup} on its own, or dig +stats, which reports the lookup time separately from everything else.
See also
Stop memorizing curl's -w format strings — describe what you want to measure and CliAI writes the command. Install it in one line.