The command
curl -v https://httpbin.org/get
Flags that show more, or less
| Flag | What it does |
|---|---|
-v, --verbose | Connection details, request headers and response headers, written to stderr. |
-i, --include | Response headers in front of the body, on stdout. No request headers. |
-I, --head | Sends a HEAD request, so only response headers come back. |
-D file | Saves the response headers to a file. Use -D - for stdout. |
--trace-ascii file | Everything -v shows plus the bodies in both directions, as text. |
--trace file | The same as a hex dump, for binary data. |
--trace-time | Puts a timestamp in front of every verbose or trace line. |
-w format | Prints chosen facts after the transfer, such as the status code or timings. |
-s, --silent | Hides the progress meter and error messages. Add -S to keep the errors. |
The three kinds of line
Every line of verbose output starts with a marker. An asterisk is curl talking about itself: the address it resolved, the connection it opened, the TLS version and certificate it negotiated, whether it reused a connection. A greater-than sign is a header line curl sent. A less-than sign is a header line it received. Lines with no marker are the response body, which is not part of the verbose output at all and is simply being printed as usual.
Read them in that order when something fails. If the asterisk lines stop early, the problem is the network or TLS and no request was ever sent. If the request lines are not what you intended, the problem is your command: a header missing, a method changed by a flag. If both look right, the answer is in the response headers.
$ curl -v https://example.com/
* Host example.com:443 was resolved.
* Trying 203.0.113.10:443...
* Connected to example.com (203.0.113.10) port 443
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* Server certificate:
* subject: CN=example.com
* expire date: ...
* SSL certificate verify ok.
> GET / HTTP/2
> Host: example.com
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/2 200
< content-type: text/html; charset=UTF-8
< content-length: 1256
<
<!doctype html>
...
Verbose output goes to stderr
Curl writes the body to standard output and the verbose lines to standard error. That split is what lets you pipe the body into another program with -v switched on and not corrupt it. It is also why curl -v … | grep appears to find nothing: the pipe carries only stdout. Merge the two streams with 2>&1 to search the verbose text, or point stderr at a file to keep a log beside the normal output.
# only the header lines, sent and received
curl -sS -o /dev/null -v https://httpbin.org/get 2>&1 | grep -E '^[<>]'
# keep the body on screen, save the conversation
curl -v https://httpbin.org/get 2> verbose.log
When you only want the headers or the status
Verbose mode is more than you need for the commonest question, which is what the server answered. -i prints the status line and response headers above the body. -D - with the body discarded gives the response headers of a real GET, which can differ from what a HEAD request returns. And a -w format prints the status code alone, which is the form to use in a script.
curl -i https://httpbin.org/status/204
curl -sS -D - -o /dev/null https://httpbin.org/get
curl -sS -o /dev/null -w '%{http_code}\n' https://httpbin.org/status/404
Seeing the request body: --trace-ascii
-v shows the headers curl sent and never the body it sent after them. When the question is whether your JSON left the machine intact, or what a -d value looked like after the shell had finished with it, use --trace-ascii. It logs every byte in both directions with a line saying which direction and how many bytes. Give it a file name, or a dash to print to the terminal. --trace-time adds a timestamp to each line, which shows where a slow request spends its time: a gap before the first received header is the server working, a gap before the connection line is the network.
curl --trace-ascii - -H 'Content-Type: application/json' -d '{"name":"Ada"}' https://httpbin.org/post
curl -v --trace-time https://httpbin.org/delay/1
Timing without the noise
For numbers instead of a log, -w reports how long each phase took, as seconds counted from the start of the request. Subtract neighbouring values to get the length of a phase: the TLS handshake is the difference between the connect and appconnect figures.
curl -sS -o /dev/null https://httpbin.org/get \
-w 'dns %{time_namelookup} tcp %{time_connect} tls %{time_appconnect} first byte %{time_starttransfer} total %{time_total}\n'
Common mistakes
- Verbose output contains your credentials. The
Authorizationheader and cookies you sent are among the request lines. Remove them before pasting a log into a ticket or a chat. - Expecting the request body in
-v. It is not there. Use--trace-ascii. - Combining
-vwith--trace. They are alternatives; curl uses one and warns about the other. - Reading HTTP/2 output with HTTP/1.1 expectations. Header names are lower case and the status line has no reason phrase:
< HTTP/2 200, not200 OK. - Using
-salone in a script. It hides error messages as well as the progress meter, so a failure prints nothing. Write-sS.
Related curl examples
Curl HEAD Request Example
HEAD asks for the headers a GET would return and nothing else.
Curl Send Header Example
-H adds a header line to the request.
Curl Timeout Example
By default curl puts no limit on how long a transfer may take, so one silent server can hang a script indefinitely.
Curl Commands
The commands people reach for most, in one place and ready to copy.
HTTP Headers
What the request and response header lines in verbose output mean.
All Curl Examples
49 worked examples, grouped by what you are trying to do.
More under Network behaviour
References
- curl man page: -v — Verbose mode and the meaning of its line prefixes.
- curl man page: --trace-ascii — A full trace of sent and received data, as text.
- curl man page: --trace-time — Timestamps on verbose and trace output.
- curl man page: -w — Every --write-out variable, including status code and timings.
These links leave api-tester.com, which is independent of the projects they point to.
FAQ
What does curl -v do?
It turns on verbose mode. Curl prints details of the connection, the request headers it sends and the response headers it receives, each line marked with *, > or <. The output goes to stderr and the body still goes to stdout.
What do the *, > and < symbols mean in curl verbose output?
An asterisk marks informational lines from curl itself, such as DNS, connection and TLS details. A greater-than sign marks request headers sent to the server, and a less-than sign marks response headers received from it.
How do I show only the response headers in curl?
Use curl -I to send a HEAD request, or curl -sS -D - -o /dev/null to send a normal GET and print only its headers. Use curl -i to print the headers followed by the body.
How do I see the request body curl sent?
Use --trace-ascii followed by a file name, or a dash for the terminal. Unlike -v, it logs the bodies as well as the headers in both directions.
Why can I not grep the output of curl -v?
Because verbose output is written to stderr and a pipe carries only stdout. Add 2>&1 before the pipe to merge the two streams.