/commands/curl/curl-show-response-headers
curl -I / curl -i: show the HTTP response headers
- 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:
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
| Command | Prints |
|---|---|
| curl -I URL | Headers of a HEAD request |
| curl -i URL | Headers and body of a GET |
| curl -s -D - -o /dev/null URL | Headers of a GET, no body |
| curl -sI URL | grep -i content-type | One header (header names are case-insensitive) |
| curl -LI URL | Headers of every redirect step, then of the final response |
| curl -s -o /dev/null -w '%{http_code}' URL | Only the status code |
| curl -s -o /dev/null -w '%header{server}' URL | Only one header value (curl 7.84+) |
| curl -v URL | Request and response headers, with > and < |
| curl -D headers.txt -O URL | Save the headers to a file while downloading |
Pitfalls
- HEAD is not GET. Servers may answer
HEADwith another status, noContent-Length, or405. When a header looks wrong, check it with the-D -form. -Iwith-dor-X POSTis contradictory: curl refuses-Itogether with-d(You can only select one HTTP request method!). Use-ifor POST requests.- Redirects. Without
-Lyou see the headers of the redirect (301,302and aLocationheader), not those of the target page. - Windows PowerShell 5.1 maps
curltoInvoke-WebRequest; runcurl.exe -I URLto 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.