Skip to content

/commands/curl/curl-show-response-headers

curl -I / curl -i: show the 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
curl
versions
curl 7.x, curl 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. To see the headers of a real GET without the body, use curl -s -D - -o /dev/null URL: -D - dumps the headers to standard output and -o /dev/null throws the body away. -v shows the request headers too, and -w '%{http_code}' prints just the status code.

Example

A Node.js server on 127.0.0.1 answers every request; it does not send a Date header so that the output is the same on every run:

bash
cat > server.js <<'EOF'
const s = require("http").createServer((req, res) => {
  res.sendDate = false;
  res.writeHead(200, { "Content-Type": "text/plain", "Cache-Control": "max-age=60" });
  res.end(req.method === "HEAD" ? "" : "hello\n");
});
s.listen(5141, "127.0.0.1");
setTimeout(() => process.exit(0), 15000);
EOF
node server.js &
sleep 1
U=http://127.0.0.1:5141/
echo "--- curl -I"
curl -s -I "$U" | tr -d '\r'
echo "--- curl -i"
curl -s -i "$U" | tr -d '\r'
echo "--- curl -D - -o /dev/null"
curl -s -D - -o /dev/null "$U" | tr -d '\r'
echo "--- status code"
curl -s -o /dev/null -w '%{http_code} %{content_type}\n' "$U"

Output

--- curl -I
HTTP/1.1 200 OK
Content-Type: text/plain
Cache-Control: max-age=60
Connection: keep-alive
Keep-Alive: timeout=5

--- curl -i
HTTP/1.1 200 OK
Content-Type: text/plain
Cache-Control: max-age=60
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked

hello
--- curl -D - -o /dev/null
HTTP/1.1 200 OK
Content-Type: text/plain
Cache-Control: max-age=60
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked

--- status code
200 text/plain

-I printed the status line and the headers. -i added the body after the blank line that ends the headers. The -D - form shows what a normal GET returns, including Transfer-Encoding: chunked, which a HEAD response does not carry here. The tr -d '\r' only removes the carriage returns that end every HTTP header line.

Options

CommandPrints
curl -I URLHeaders of a HEAD request
curl -i URLHeaders and body of a GET
curl -s -D - -o /dev/null URLHeaders of a GET, no body
curl -sI URL | grep -i content-typeOne header (header names are case-insensitive)
curl -LI URLHeaders of every redirect step, then of the final response
curl -s -o /dev/null -w '%{http_code}' URLOnly the status code
curl -s -o /dev/null -w '%header{server}' URLOnly one header value (curl 7.84+)
curl -v URLRequest and response headers, with > and <
curl -D headers.txt -O URLSave the headers to a file while downloading

Pitfalls

  • HEAD is not GET. Servers may answer HEAD with another status, no Content-Length, or 405. When a header looks wrong, check it with the -D - form.
  • -I with -d or -X POST is contradictory: curl refuses -I together with -d (You can only select one HTTP request method!). Use -i for POST requests.
  • Redirects. Without -L you see the headers of the redirect (301, 302 and a Location header), not those of the target page.
  • Windows PowerShell 5.1 maps curl to Invoke-WebRequest; run curl.exe -I URL to use real curl.

Read the result

The first line is the status: HTTP/1.1 200 OK, or HTTP/2 200 over HTTP/2 where no reason phrase is sent. A status of 400 or more does not make curl fail unless you add -f; combine -f with -w '%{http_code}' in scripts that must stop on errors.

FAQ

Why does curl -I return 405 or different headers than a normal request?

-I sends a HEAD request, and some servers or frameworks handle HEAD differently or reject it with 405 Method Not Allowed. Use curl -s -D - -o /dev/null URL to send a normal GET and print only the headers.

How do I print only the status code?

curl -s -o /dev/null -w '%{http_code}\n' URL. -w writes the variable after the transfer, -o /dev/null discards the body, and -s hides the progress meter.

How do I see the request headers that curl sends?

Use -v. Lines starting with > are the request, lines with < the response, and lines with * are curl's own messages such as the TLS handshake. --trace-ascii FILE records everything, including the bodies.

Sources