Skip to content

cURL headers: send, show and debug HTTP headers

Send, change, remove and read HTTP headers with curl. Every command run on 10 October 2026, with proxy headers and redirects tested on a stub proxy.

HProxy TeamOctober 10, 2026Updated October 10, 202610 min read

cURL headers: send, show and debug HTTP headers

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 October 10, 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.

Our own run on our server, October 10, 2026, 19:51 UTC: curl 8.5.0 on Ubuntu 24.04, captured off-screen. Each command is printed before its output, then its exit code.

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.

Our own run on our server, October 10, 2026, 19:52 UTC: curl 8.5.0 on Ubuntu 24.04, captured off-screen.
What you wantCommandWhat curl sends
The headers alonecurl -I URLA HEAD request.
The headers of a normal GETcurl -s -D - -o /dev/null URLA GET, and the body is thrown away.
Headers and body togethercurl -i URLA GET.
One header, or all as JSONcurl -s -o /dev/null -w '%header{content-type}' URLA 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:

CommandStatusExit code
curl -s --http1.1 -X HEAD -m 5 https://example.com/20028. curl waited until the limit.
curl -s -X HEAD -m 5 https://example.com/ (HTTP/2)2000. 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.

Our own run on our server, October 10, 2026, 19:52 UTC: curl 8.5.0 on Ubuntu 24.04, a stub proxy and an echo server we wrote, both listening on 127.0.0.1.
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 addressThe site receivedThe proxy received
https://httpbin.org/headersX-Site only.CONNECT httpbin.org:443 with X-Note and the login.
http://httpbin.org/headersX-Site and X-Note.GET http://httpbin.org/headers with both headers and the login.
-⁠H for the site, -⁠-⁠proxy-⁠header for the proxy: who received what
The site receivedThe proxy received
https://httpbin.org/headersX-Site onlyCONNECT with X-Note and the login
http://httpbin.org/headersX-Site and X-NoteThe GET with both headers and the login
Source: HProxy, curl 8.5.0 through our stub proxy · hproxy.comProxy.

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 seeWhyWhat to do
A help text that ends in Invalid category provided-h (lower case) is help, not headerUse -H.
Cannot bind parameter 'Headers'Windows PowerShell 5.1 ran Invoke-WebRequestType curl.exe, as What is cURL? shows.
A header that never arrives, exit code 0The command was copied with curly quotes ‘ ’Retype the quotes as plain ' or ".
The proxy header reached the sitePlain http:// through a proxy is one requestUse an https:// address, or keep secrets out of proxy headers.
Authorization missing after -Lcurl drops it on a redirect to another hostAdd --location-trusted, only for hosts you trust.
curl -X HEAD hangs, then exit 28-X changes the method word onlyUse -I.
Headers differ from what the page gets-I sent HEAD, the page uses GETUse -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 behavior 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 January 10, 2027.

Sources

  • The curl man page, published by the curl project for version 8.23.0, read October 10, 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 January 20, 2026: learn.microsoft.com.
  • Amazon Web Services, request tracing for Application Load Balancers, read October 10, 2026: docs.aws.amazon.com.
  • Stack Overflow, "Curl header request returning 404 but body returning 200", asked June 13, 2014, read through the Stack Exchange API on October 10, 2026.
  • Our own runs of October 10, 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.

Frequently asked questions

How do I send a header with curl?

Add -H with the name and the value, for example curl -H 'X-Api-Key: 123' https://example.com/. Repeat -H for each header, or put one header per line in a file and pass -H @headers.txt. A header with the name of one curl sets itself, such as User-Agent, replaces curl's own.

How do I see the response headers with curl?

Use -I for the headers alone, which sends a HEAD request. Use -i for the headers and the body together. To see the headers of a normal GET without the body, use -D - -o /dev/null. For one header, use -w '%header{content-type}', available from curl 7.84.0.

How do I remove a header that curl sends by default?

Write the name with a colon and nothing after it, for example -H 'User-Agent:'. curl then leaves the header out. To send a header with an empty value instead, end the name with a semicolon: -H 'X-Empty;'.

How do I see the request headers curl sends?

Run curl -v and look at the lines that start with >. Over HTTP/2, curl lists the request as lines such as [HTTP/2] [1] [user-agent: curl/8.5.0], with lowercase names and the pseudo-headers :method, :scheme, :authority and :path.

Why does curl -X HEAD hang?

-X only changes the word in the request line. curl still waits for the body the response headers announce, and a HEAD response has none. Over HTTP/1.1 our test hung until its 5-second limit and exited with code 28. Use -I for a HEAD request.

Does curl send my headers again after a redirect?

Yes. Headers set with -H go to every host curl follows with -L. Authorization and Cookie headers set with -H are the exception: curl drops them when the redirect goes to another host, unless you add --location-trusted. Our test showed both.

How do I send a header only to the proxy?

Use --proxy-header instead of -H. For an https:// address, curl puts it only in the CONNECT request to the proxy. For a plain http:// address there is one request, and in our test the site received the proxy header as well.

Get proxies that are alive right now

Our free proxy list re-checks every exit every few minutes across 100+ countries, with a live last-checked time, so you copy IPs that worked moments ago, not a stale text dump. When the location has to survive a real check, the paid network holds up.

129M+ proxy checks run · 100+ countries · HTTP / HTTPS / SOCKS · re-checked every few minutes · no signup

HProxy.

Honest guides and comparisons on proxies, scraping and staying unblocked, from the team that runs the network.

RSS feed