Skip to content

/commands/http/show-http-response-headers

curl -I vs -i vs -v: show HTTP response headers

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · curl 8.21.0 (x86_64-w64-mingw32) libcurl/8.21.0 Schannel zlib/1.3.2updated
tool
HTTP
versions
curl 7.x – 8.x
os
linux, macos, windows

curl -I URL sends a HEAD request and prints only the response headers. curl -i URL sends the normal GET and prints the headers followed by the body. curl -sS -D - -o /dev/null URL prints the headers of any request (also POST) and discards the body, which is the safest choice when the server treats HEAD differently from GET.

Compare the options

A small local server (port 5035) answers every request:

bash
cat > server.js <<'EOF'
require("http").createServer((req, res) => {
  res.setHeader("Content-Type", "application/json");
  res.setHeader("Cache-Control", "no-store");
  res.end(JSON.stringify({ method: req.method }) + "\n");
}).listen(5035, "127.0.0.1");
setTimeout(() => process.exit(0), 5000);
EOF
node server.js &
sleep 1
hide_date() { grep -v -i '^date:'; }
echo "--- curl -I (HEAD, headers only)"
curl -sI http://127.0.0.1:5035/ | hide_date
echo "--- curl -i (GET, headers + body)"
curl -si http://127.0.0.1:5035/ | hide_date
echo "--- curl -D - -o /dev/null with POST"
curl -sS -D - -o /dev/null -X POST http://127.0.0.1:5035/ | hide_date

Output

--- curl -I (HEAD, headers only)
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Connection: keep-alive
Keep-Alive: timeout=5

--- curl -i (GET, headers + body)
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Connection: keep-alive
Keep-Alive: timeout=5
Content-Length: 17

{"method":"GET"}
--- curl -D - -o /dev/null with POST
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Connection: keep-alive
Keep-Alive: timeout=5
Content-Length: 18

The Date header is filtered out because it changes on every request. Note that the HEAD response has no body even though the server wrote one: HTTP forbids a body in responses to HEAD.

Options

OptionMethodShows
-I, --headHEADResponse headers only
-i, --includeunchanged (GET by default)Response headers, then the body
-D FILE, --dump-header FILEunchangedHeaders written to FILE (- for stdout)
-v, --verboseunchangedRequest headers (>), response headers (<), connection and TLS info
-w "%{http_code}"unchangedOnly selected values, such as the status code
-LunchangedFollow redirects; with -I or -i shows the headers of every hop

Which one to use

  • Quick look at a page or file: curl -I. It downloads nothing, so it is fast even for large files, and it shows Content-Length, Last-Modified, ETag and cache headers.
  • Debugging an API call: curl -i with the same method, headers and body your application sends, so you see the exact response including the error body.
  • Scripts: -D - (or -D headers.txt) with -o for the body keeps headers and body apart, and works with any method.
  • Connection, TLS or redirect problems: curl -v. Lines starting with > are what curl sent, < what it received, and * are curl's own notes (DNS, TLS handshake, certificate). The verbose output goes to stderr, so use curl -v URL 2>&1 | grep '^<' to filter it.

Pitfalls

  • -I selects the HEAD method, so it cannot be combined with options that select another one, such as -d (which means POST). curl refuses before connecting:
bash
curl -I -d 'name=demo' http://127.0.0.1:5036/ 2>&1; echo "exit status: $?"

Output

Warning: You can only select one HTTP request method! You asked for both POST
Warning: (-d, --data) and HEAD (-I, --head).
exit status: 2

Use -i or -D - -o /dev/null with the data instead.

  • Over HTTP/2 and HTTP/3, header names arrive in lower case (content-type), and the status line reads HTTP/2 200 with no reason phrase. Match header names case-insensitively (grep -i).
  • Without -L, a redirect shows only the 301 or 302 response and its Location header, not the final page.
  • In Windows PowerShell 5.1, curl is an alias for Invoke-WebRequest, which does not accept these options. Run curl.exe explicitly; on Windows use -o NUL where Unix uses -o /dev/null.

Only the status code

bash
curl -s -o /dev/null -w '%{http_code}\n' https://www.openssl.org/

FAQ

How do I see the request headers curl sends?

Use curl -v. Lines starting with > are the request line and headers curl sent; lines starting with < are the response.

How do I show only one header?

Dump the headers and filter them, for example curl -sI URL | grep -i '^content-type'. Use -D - -o /dev/null instead of -I if the server treats HEAD differently.

Can curl print the headers of every redirect?

Yes. Combine -L with -I, -i or -D -: curl prints one header block per response, from the first redirect to the final page.

Sources