How to check content-encoding
Print the response headers and read one line: curl -s -D - -o /dev/null -H 'accept-encoding: gzip, br' https://example.com/ | grep -i content-encoding. The token names how the body was transformed. An absent header means identity, the untransformed body, which is the default the specification assumes.
Why check this
Content-Encoding is the header that decides whether a client can read the bytes at all. A gateway that adds the header without compressing, or a service that compresses twice through two proxies, produces a body no decoder accepts, and the symptom reaches you as an intermittent parse error in one client library and not another. Read it in regression on every route that changed proxy, gateway or CDN configuration, and read it alongside the byte counts so a header that lies gets caught.
Prerequisites
- curl 7.21 or later for the header read. Any build works.
- curl with brotli for the ratio measurement in step 4.
curl --versionlists it. - The MDN Content-Encoding reference and RFC 9110 section 8.4, which define the token list and the
identitydefault.
Steps
- Step 1.
Read the header on a route that compresses, and keep the size lines with it.
curl -s -H 'accept-encoding: gzip' -D - -o /dev/null 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS' | grep -i -E 'content-encoding|content-length|stored-content'x-goog-stored-content-encoding: identity x-goog-stored-content-length: 258732 content-encoding: gzip content-length: 36546This origin exposes both numbers.
content-length: 36546is what travels; 258732 is what the object is at rest. Theidentitytoken in the storage header is the spelling for "no transformation". - Step 2.
Read the same header on a route that does not compress.
curl -s -H 'accept-encoding: gzip' -D - -o /dev/null https://httpbin.org/html | grep -i -E '^HTTP|content-encoding|content-length'HTTP/2 200 content-length: 3741No header at all. Servers signal "uncompressed" by omitting
Content-Encoding, not by sendingidentity, so an empty grep is the normal negative answer rather than a broken command. - Step 3.
Separate
Content-EncodingfromTransfer-Encodingby forcing HTTP/1.1.curl -s --http1.1 -H 'accept-encoding: gzip' -D - -o /dev/null https://www.cloudflare.com/ | grep -i -E '^HTTP|encoding'HTTP/1.1 200 OK Transfer-Encoding: chunked Vary: accept-encoding Content-Encoding: gzipBoth appear on one response and they are independent.
Transfer-Encoding: chunkeddescribes how the message was framed on this hop and says nothing about compression. HTTP/2 has noTransfer-Encodingat all, which is why the same URL over h2 shows onlycontent-encoding. - Step 4.
Measure the ratio: the same document raw, then with each encoding.
for e in identity gzip br; do curl -s -o /dev/null -H "accept-encoding: $e" -w "$e %{size_download}\n" 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS'; doneidentity 258732 gzip 36546 br 30865258732 against 30865 is a ratio of 8.4 to 1. A Chrome DevTools capture of the same page on this machine reported
encodedBodySize30865 anddecodedBodySize258732, the same two numbers, so the browser and curl agree byte for byte.
How to read the result
| What you see | What it means | What to do |
| --- | --- | --- |
| content-encoding: gzip or br | The body was compressed in transit | Compare the byte counts before trusting it. A header is a claim. |
| Header absent | The body is identity, untransformed | Expected on images and video. A defect on HTML, CSS, JS and JSON. |
| content-encoding: identity spelled out | Legal and rare | Treat it as uncompressed. Some storage layers write it, most omit the header. |
| Transfer-Encoding: chunked alone | Framing, not compression | Do not report it as compression. Look for Content-Encoding separately. |
| Two tokens, gzip, gzip | The body was compressed twice | A bug. Decoders apply them in order and most clients give up. Find the second proxy. |
Common mistakes
What to check next
- How to check if gzip is enabled: the encoding every client accepts, and how to prove it saved bytes.
- How to check if brotli is enabled: the encoding a server prefers when the client offers it.
- How to check vary header: the header that keeps a shared cache from mixing the two.
- How to check HTTP response headers with curl: the general form of the header dump used in every step here.
- Gzip compression test: prints the encoding and both sizes per resource type.
FAQ
How to check the compression ratio of a response?
Request the URL twice, once with accept-encoding: identity and once with the encoding you care about, and divide the two %{size_download} values. Step 4 does it in one line. The header alone gives no ratio.
How to check if a resource is compressed?
Read content-encoding on that resource, not on the page that loads it. Compression is configured per MIME type, so the HTML can be compressed while a JSON or SVG response from the same host is not.
Does an absent Content-Encoding mean the response is broken?
No. Absent means identity, the untransformed body, which RFC 9110 treats as the default. It is correct on already-compressed formats such as JPEG, WOFF2 and MP4, and a defect on text.
Is Transfer-Encoding: chunked a form of compression?
No. It describes message framing on one hop, so the sender can start writing before it knows the length. A response can be chunked and uncompressed, compressed and not chunked, or both at once, as step 3 shows.
Verified
Verified by Maks Vernycurl 8.21.0
Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.
Related on this site
basic5 minpublished updated Maks Verny