To send a header with curl, add -H 'Name: value'. To read the headers a server sends back, use -I for the headers alone or -i for headers and body. -v shows your own request headers as well. The same -H replaces a header curl sets itself, and -H 'Name:' removes it.
We ran every command on this page on 10 October 2026, with curl 8.5.0 on Ubuntu 24.04. httpbin.org/headers answered with the headers it received, and example.com supplied the response headers. A stub proxy and a small echo server on our own server showed which headers reach a proxy and which survive a redirect.
How do you send a header with curl?
You need curl in a terminal; What is cURL? shows how to check your version. Each step below shows the command and the answer httpbin gave.

Step 1: see what curl sends by default
curl -s https://httpbin.org/headers
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/8.5.0",
"X-Amzn-Trace-Id": "Root=1-6aca971f-0e31a64870d682f756ca89ba"
}
}
curl sent three headers: Host, User-Agent with its own name and version, and Accept: */*. It did not send X-Amzn-Trace-Id. AWS documents that header as one its load balancers add before passing a request on, so it tells you about httpbin's side, not yours.
Step 2: add a header
curl -s -H 'X-Request-Source: docs-test' https://httpbin.org/headers
The header arrived as "X-Request-Source":"docs-test". Repeat -H for every header you need. Header names are case-insensitive under RFC 9110, so x-request-source works the same.
Step 3: replace a header curl sets itself
curl -s -H 'User-Agent: my-tool/1.0' https://httpbin.org/headers
When your header has the name of one curl would send, the manual says curl uses yours instead. httpbin saw "User-Agent":"my-tool/1.0". For the common ones there are shortcuts: -A sets User-Agent, -e sets Referer and -b sends cookies.
Step 4: remove a header
curl -s -H 'User-Agent:' -H 'Accept:' https://httpbin.org/headers
A name with a colon and nothing after it removes the header. httpbin received only Host and its own trace header.
Step 5: send a header with an empty value
curl -s -H 'X-Empty;' https://httpbin.org/headers
A semicolon instead of the colon sends the header with no value, and httpbin showed "X-Empty":"". The two forms are easy to mix up: the colon removes, the semicolon sends empty.
Step 6: read headers from a file
printf 'X-One: 1\nX-Two: 2\n' > headers.txt
curl -s -H @headers.txt https://httpbin.org/headers
With @ and a file name, -H adds one header for each line of the file. Both X-One and X-Two arrived. This keeps tokens out of your shell history.
How do you show the response headers?
curl offers four ways, and they do not send the same request.

| What you want | Command | What curl sends |
|---|---|---|
| The headers alone | curl -I URL | A HEAD request. |
| The headers of a normal GET | curl -s -D - -o /dev/null URL | A GET, and the body is thrown away. |
| Headers and body together | curl -i URL | A GET. |
| One header, or all as JSON | curl -s -o /dev/null -w '%header{content-type}' URL | A GET. |
-I sends HEAD, not GET
curl -sI https://example.com/
HTTP/2 200
date: Sat, 10 Oct 2026 19:51:34 GMT
content-type: text/html; charset=utf-8
server: cloudflare
last-modified: Fri, 09 Oct 2026 20:18:28 GMT
allow: GET, HEAD
accept-ranges: bytes
age: 517
cf-cache-status: HIT
cf-ray: a48829193bf24d23-ORD
alt-svc: h3=":443"; ma=86400
RFC 9110 defines HEAD as GET without the content, so the headers should match. Servers do not always follow that: a Stack Overflow question from 2014 asks why a HEAD request returned 404 while the full request returned 200. When the headers of the real GET matter, use -D - -o /dev/null. On example.com both ways printed the same status line and the same ten headers.
-i prints the headers and the body
-i puts the headers in front of the body. It was called --include before curl 8.10.0, and the old name still works.
-w picks one header, or all of them
curl -s -o /dev/null -w '%header{content-type}\n' https://example.com/
curl -s -o /dev/null -w '%{header_json}\n' https://example.com/
The first printed text/html; charset=utf-8. The second prints every response header as JSON, with each value in a list, such as "server":["cloudflare"]. %header{} needs curl 7.84.0 and header_json needs 7.83.0, so check older builds first.
-X HEAD is not the same as -I
The manual warns that -X HEAD does not make a proper HEAD request. It only changes the method word, and curl still waits for the body that the headers announce. We tried it with a 5-second limit:
| Command | Status | Exit code |
|---|---|---|
curl -s --http1.1 -X HEAD -m 5 https://example.com/ | 200 | 28. curl waited until the limit. |
curl -s -X HEAD -m 5 https://example.com/ (HTTP/2) | 200 | 0. curl stopped at once. |
Over HTTP/2 the server marks the end of the stream, so curl stopped. Over HTTP/1.1 it waited for bytes that never came. -I avoids the problem on both.
How do you see the headers curl sent?
-v prints the whole exchange. Lines that start with > are headers curl sent, and lines with < are headers it received. Over HTTP/1.1:
$ curl -sv --http1.1 -o /dev/null https://example.com/ 2>&1 | grep '^> '
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/8.5.0
> Accept: */*
Over HTTP/2, curl lists the request differently:
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: example.com]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.5.0]
* [HTTP/2] [1] [accept: */*]
The names are lowercase, because RFC 9113 requires lowercase field names in HTTP/2. Host became the :authority pseudo-header. A service that insists on a certain capitalization will see lowercase names over HTTP/2 either way.
Which headers reach the proxy, and which the site?
-H is for the site, and --proxy-header is for an HTTP proxy. We sent one of each through a stub proxy on our server that asked for the login USER:PASS and logged what it received.

curl -s -x http://127.0.0.1:18081 -U USER:PASS --proxy-header 'X-Note: for-proxy' -H 'X-Site: for-site' https://httpbin.org/headers
| Target address | The site received | The proxy received |
|---|---|---|
https://httpbin.org/headers | X-Site only. | CONNECT httpbin.org:443 with X-Note and the login. |
http://httpbin.org/headers | X-Site and X-Note. | GET http://httpbin.org/headers with both headers and the login. |
For an https:// address, curl asks the proxy for a tunnel with CONNECT and puts --proxy-header headers in that request only. The site's own headers travel inside the encrypted tunnel. For a plain http:// address there is a single request, which the proxy passes on. RFC 9110 says a proxy must forward header fields it does not recognize, so the site received X-Note too. Keep secrets meant for a proxy away from plain HTTP.
The proxy login itself travels as a Proxy-Authorization header, which curl builds from -U. Our guide to using proxies with curl covers the flags in full, and 407 Proxy Authentication Required covers a refused login. With a real gateway the flags stay the same: -x http://premium.hproxy.com:10000 -U USER:PASS. The login comes from your dashboard, as on our residential proxies.
Which headers survive a redirect?
With -L, curl sends your -H headers to every address it follows, even on another host. The manual makes one exception: Authorization and Cookie set with -H stay behind when the redirect leaves the original host. We had httpbin.org redirect curl to the echo server on our own machine:
curl -sL -H 'Authorization: Bearer PLACEHOLDER' -H 'X-Site: for-site' 'https://httpbin.org/redirect-to?url=http://127.0.0.1:18090/echo'
echo server on 127.0.0.1 received:
Host: 127.0.0.1:18090
User-Agent: curl/8.5.0
Accept: */*
X-Site: for-site
X-Site followed the redirect, and Authorization did not. With --location-trusted added, the echo server received Authorization: Bearer PLACEHOLDER as well. Use that option only when you trust every host in the chain. Custom headers such as X-Api-Key get no such protection, so keep secrets out of them when a redirect might leave the site. Following redirects with curl covers logins given with -u and cookies.
What goes wrong most often?
| What you see | Why | What to do |
|---|---|---|
A help text that ends in Invalid category provided | -h (lower case) is help, not header | Use -H. |
Cannot bind parameter 'Headers' | Windows PowerShell 5.1 ran Invoke-WebRequest | Type curl.exe, as What is cURL? shows. |
| A header that never arrives, exit code 0 | The command was copied with curly quotes ‘ ’ | Retype the quotes as plain ' or ". |
| The proxy header reached the site | Plain http:// through a proxy is one request | Use an https:// address, or keep secrets out of proxy headers. |
Authorization missing after -L | curl drops it on a redirect to another host | Add --location-trusted, only for hosts you trust. |
curl -X HEAD hangs, then exit 28 | -X changes the method word only | Use -I. |
| Headers differ from what the page gets | -I sent HEAD, the page uses GET | Use -D - -o /dev/null. |
The curly quotes case is quiet. In our run the shell split ‘X-Test: 1’ in two, curl treated 1’ as a second address and failed it with exit 6. It never sent X-Test and still finished with exit code 0.
What this page could not check
We ran one curl build, 8.5.0 on Ubuntu 24.04, and newer behaviour comes from the manual. Our response headers came from example.com and httpbin.org, which both sit behind large front ends that add or change headers. The proxy was our own stub, which forwards every header it does not know; a real proxy may strip or add some. We did not find a server that answers HEAD and GET differently on the day. That case rests on RFC 9110 and a Stack Overflow report. The -X HEAD hang was one server and one run each way. curl changes option names and -w variables between versions, so we will check this page again by 10 January 2027.
Sources
- The curl man page, published by the curl project for version 8.23.0, read 10 October 2026: curl.se/docs/manpage.html.
- RFC 9110, HTTP Semantics, June 2022, for field names, HEAD and how proxies forward fields: rfc-editor.org/rfc/rfc9110.
- RFC 9113, HTTP/2, June 2022, for lowercase field names: rfc-editor.org/rfc/rfc9113.
- Microsoft Learn, Invoke-WebRequest for Windows PowerShell 5.1 (its aliases curl and wget), updated 20 January 2026: learn.microsoft.com.
- Amazon Web Services, request tracing for Application Load Balancers, read 10 October 2026: docs.aws.amazon.com.
- Stack Overflow, "Curl header request returning 404 but body returning 200", asked 13 June 2014, read through the Stack Exchange API on 10 October 2026.
- Our own runs of 10 October 2026, with curl 8.5.0 on Ubuntu 24.04. They went to httpbin.org and example.com, through a stub proxy and to an echo server we wrote. The research folder for this page holds every transcript, capture and script.


