curl Headers: How to See Request and Response Headers
A header is a short line of information that travels alongside a web page but never shows up on the page itself: the server type, how long a browser should cache the file, whether the content is compressed, what status code came back. MDN's HTTP headers reference is a good place to see the full catalogue. When you need to see those curl headers directly, without opening browser developer tools or squinting at a Network tab, the terminal is often the faster route, especially for a script, a cron job, or a server with no browser attached to it at all.
Curl gives you four or five different ways to look at headers, and most tutorials just list the flags without saying which one answers which question. This guide is organized the other way around: what you're trying to find out, then the exact command for that. By the end you'll know how to show headers only, how to see headers and body together, how to send a custom header, and why curl -I sometimes lies to you about what a page actually returns.
How Do I Show Response Headers with curl?
The short answer: run curl -I followed by the URL. The -I flag (long form --head) tells curl to send an HTTP HEAD request instead of a normal GET. A HEAD request asks the server "what would you send me?" without asking it to actually send the body, so curl gets back nothing but headers. It's the fastest way to check curl headers when you don't care about the page content, just its metadata.
- Open a terminal (Terminal on macOS, PowerShell or Command Prompt on Windows, or your usual shell on Linux) and type the command below, replacing the URL with the page you want to check.
Press enter. If curl is installed, you should see a block of text start with something likecurl -I https://example.comHTTP/2 200followed by lines likecontent-type,date, andcache-control. If instead you get "command not found," curl isn't installed or isn't on your system's PATH; on Windows 10 and 11 it usually ships with the OS already, so try opening a fresh terminal window first. - Read the first line. It tells you the HTTP version and the status code, for example
HTTP/2 200means success, whileHTTP/1.1 301 Moved Permanentlymeans the server redirected you somewhere else. If you see a 3xx code here and expected a 200, that's not a bug in curl, it's the server telling you the URL you asked for has moved. The status code reference on httpcheck.tools breaks down what each range means if you land on one you don't recognize. - Scan the rest for the header you actually need. Looking for caching behavior? Check
cache-controlandetag. Checking if compression is on? Look forcontent-encoding: gziporbr. If the output is completely empty, or the terminal just sits there with a blinking cursor, that's a real problem and not something you did wrong; the troubleshooting section further down covers exactly why that happens.
One thing worth flagging early: not every server answers HEAD requests the same way it answers GET requests, and some don't support HEAD at all. That gap is common enough that it gets its own section later in this guide, with a more reliable workaround.
What is the difference between curl -I and curl -i?
This is one of the most common points of confusion, mostly because the two flags differ by a single letter's case. They are not the same thing.
| Flag | What it does | What you see |
|---|---|---|
-I (--head) | Sends a HEAD request; server is asked not to send a body | Headers only, no page content |
-i (--show-headers) | Sends a normal GET request, then prints headers before the body | Headers followed by the full page content |
Here's a detail almost no other tutorial mentions: as of curl version 8.10.0, the official long name for -i changed to --show-headers. The older name, --include, still works, but it's now a legacy alias rather than the canonical spelling documented in the manual. If you're reading a curl man page or script written after that release and see --show-headers, that's the same flag as -i, just with clearer wording. This is documented in the official curl manpage, which is worth bookmarking as the single source of truth for flag behavior, since it's versioned and updated with every release.
If you only remember one rule from this section, make it this: capital -I means "just the headers, hold the body." Lowercase -i means "headers, then the body too."
Seeing headers without losing the body (-i and -v)
Sometimes headers alone don't answer your question. Maybe you need to confirm the page's headers look right and also glance at the HTML itself, or you need to see what curl actually sent, not just what it got back. Two flags cover this.
- -i prints response headers, a blank line, then the full response body in one continuous stream. Good for a quick "let me see both" check without running two separate commands.
- -v (
--verbose) prints the entire exchange: request headers prefixed with>, response headers prefixed with<, and connection or TLS details prefixed with*. It's the only single flag that shows both sides of the conversation, which makes it the one to reach for when you suspect the problem is in what curl is sending, not just what it's getting back.
curl -v https://example.com
Run that and look for lines starting with > near the top. Those are the request headers curl sent before the server ever replied, including the User-Agent and Accept headers it adds automatically if you don't set your own. This distinction matters more than it sounds: a header that shows up with > is something you asked for, and a header that shows up with < is something the server decided to send you regardless. The official verbose output guide from the curl project walks through each prefix in more detail if you want the full breakdown.
The more reliable way: -D and -o together
HEAD requests have a real weakness: the HTTP specification says a server's response to HEAD should be identical to its response to GET, minus the body, but "should" isn't "must," and plenty of servers don't implement it perfectly. Some return different headers for HEAD than for GET. Others return a 405 Method Not Allowed and refuse HEAD entirely. Per RFC 9110, section 9.3.2, the specification defines HEAD as GET without a response body, but implementation is left to each server, and beginners hit that gap more often than you'd expect.
The workaround is to make a real GET request and simply throw the body away instead of asking curl to fake a bodyless request.
- Run this command, replacing the URL as usual.
On Windows, swapcurl -D - -o /dev/null -s https://example.com/dev/nullforNUL:curl -D - -o NUL -s https://example.com. If it worked, you'll see only the response headers print to your terminal, with no page content mixed in. - Understand what each piece does:
-D -tells curl to dump the response headers to standard output (the terminal),-o /dev/nullsends the actual body to a location that discards it instead of printing it, and-ssilences curl's own progress meter so it doesn't clutter the output. - Compare the result to what
curl -Igave you earlier. If they match, the server handles HEAD correctly and either command works. If they differ, or if-Ireturned a 405 error while this command returns a normal 200, you've just confirmed the server doesn't support HEAD properly, and this GET-and-discard approach is the one to trust going forward for that particular site.
How do I send a custom header with curl?
Testing an API, checking how a site responds to a different user agent, or debugging an authentication issue all involve sending your own headers instead of just reading the server's. The -H flag (--header) handles this.
curl -H "Authorization: Bearer your-token-here" https://api.example.com/data
Each -H adds one header, formatted as "Header-Name: value" inside quotes. If you need to send more than one, just repeat the flag.
curl -H "Authorization: Bearer your-token-here" -H "Accept: application/json" https://api.example.com/data
Run that against an endpoint you have valid credentials for, and expect a JSON response body rather than an authentication error. If you instead get a 401, double-check the token is current and free of a stray space or line break inside the quotes; a mangled token is the most common cause.
Two other uses come up constantly. Sending a custom User-Agent to see how a page responds to a different browser or crawler:
curl -H "User-Agent: Mozilla/5.0 (compatible; TestBot/1.0)" -I https://example.com
And removing a header curl would otherwise send by default, which uses a slightly odd but consistent trick: give the header name with nothing after the colon.
curl -H "User-Agent:" https://example.com
That strips the default User-Agent curl normally sends, which is occasionally useful for testing how a server behaves when that header is missing entirely. This syntax is documented in curl's own guide to customizing headers, including the removal trick and a full list of headers curl sets automatically. For a plain-language walkthrough of what individual headers mean, from cache-control to content-security-policy, the header-by-header guide on httpcheck.tools covers each one.
How do I follow redirects with curl?
By default, curl does not follow redirects. If a page returns a 301 or 302, curl shows you that redirect response and stops there, which trips people up constantly: they run curl -I on a page they know is live, get a "301 Moved Permanently" with almost no other information, and assume the site is broken. It isn't. Curl is just doing what you told it to do: fetch that one URL and report back, not chase it anywhere else.
The -L flag (--location) tells curl to follow the redirect chain instead of stopping at the first hop.
curl -L -I https://example.com
Run that on a page you know redirects, and you should see multiple header blocks stacked on top of each other, one per hop, ending with the final page's headers at the bottom. If you only see one block, either the page didn't redirect at all, or you forgot the -L flag. This combination, -L with -I, is the closest thing curl has to a redirect-chain viewer: it shows every stop along the way using only headers, without downloading any actual page content.
Curl's default limit on redirects it will follow is documented in the manpage's --max-redirs entry, since defaults have shifted between releases. And if a chain never resolves, if curl or a browser just keeps producing hop after hop with no final 200, that's a redirect loop rather than a normal chain; the site's guide to fixing redirect loops covers why that happens and how to break it.
If you're the one who needs to create a redirect rather than just read one, say you're moving a page and need the server to send visitors to its new address, that's a job for your server's configuration file rather than curl. htaccess.tools generates the Apache directive for you if that's the stack you're running.
Common problems and what they mean
Most curl header confusion comes down to a handful of repeat offenders. Here's what each one actually means, so you can stop guessing.
- Empty output, nothing prints at all. Usually one of three things: the server doesn't support HEAD and silently drops the connection instead of returning an error, the URL redirects and you forgot
-L, or there's a typo in the URL itself (missinghttps://, for instance). Try the-D -oworkaround from earlier; if that shows headers where-Ishowed nothing, you've confirmed it's a HEAD support issue. - 405 Method Not Allowed. The server is telling you it doesn't accept HEAD requests for this URL. This is a server configuration choice, not a curl error, and the GET-and-discard method above sidesteps it entirely.
- The command hangs and never returns. This almost always happens when someone forces the method with
curl -X HEADinstead of using-I.-X HEADchanges the request line but doesn't tell curl to stop waiting for a body, so if the server ignores the instruction and sends content anyway, curl sits there waiting. Stick with-Ifor header-only requests; it handles this correctly. - A certificate or HTTPS error interrupts everything before headers ever show. The secure connection itself failed, before curl ever gets to request headers, so the fix is on the certificate side (expired, misconfigured, or self-signed), not the header flags you're using.
When curl isn't the fastest option
Curl earns its keep for scripting, automation, and quick one-off checks where opening a browser feels like overkill. But when you want the full picture, every hop in a redirect chain, timing for each stage, and every response header already grouped and explained rather than dumped as raw text, typing flags from memory stops being the fast option. httpcheck.tools does that work in one paste: drop in a URL and it shows the redirect chain hop by hop with timing, the final status, and every header grouped with a plain-language note, plus grades for caching, security headers, and content type. No terminal required.
Frequently Asked Questions
How do I show response headers with curl?
Run curl -I followed by the URL, for example curl -I https://example.com. This sends a HEAD request and prints only the response headers, no page content. If the output looks empty or wrong, the site may not support HEAD requests properly; running curl -D - -o /dev/null -s https://example.com instead sends a real GET request and discards the body, which gives more reliable results on servers that handle HEAD inconsistently.
What is the difference between curl -I and curl -i?
Capital -I sends a HEAD request and shows headers only, with no body at all. Lowercase -i sends a normal GET request and shows the headers followed by the full page content. As of curl 8.10.0, the official long name for -i is --show-headers, though the older name --include still works as an alias.
How do I send a custom header with curl?
Use the -H flag followed by the header name and value in quotes, for example curl -H "Authorization: Bearer your-token" https://api.example.com. Repeat -H for each additional header you need to send. To remove a header curl would normally send automatically, such as the default User-Agent, pass the header name with nothing after the colon: curl -H "User-Agent:" https://example.com.
How do I follow redirects with curl?
Add the -L flag (short for --location) to your command, for example curl -L -I https://example.com. Without it, curl stops at the first redirect response instead of following it to the final destination, which is the most common reason a working page looks broken when checked with curl alone. Combining -L with -I shows the headers at every hop in the redirect chain.