Content-Encoding: what compression was applied
Content-Encoding names the transformation applied to the body, almost always compression, and it stays applied end to end until the client decodes it.
At a glance
- Direction
- Response mostly, though a request body may also be encoded if the server accepts it.
- Defined in
- RFC 9110
- When absent
- The body is in its original form, exactly as the resource is defined.
- Common values
- gzip, br for Brotli, zstd, deflate, and identity for no transformation
- Scope
- End to end. It is part of the representation, not of one hop.
- Requires
- Vary: Accept-Encoding on the response, so caches keep variants apart
- Affects
- Content-Length, which counts encoded bytes, and the ETag, which identifies this variant
In detail
The header describes the payload rather than the connection. A gzipped body stays gzipped through every proxy on the path and is decoded by the client at the end, which is the opposite of Transfer-Encoding, where each hop may choose its own framing. That end to end property is why a cache can store the compressed bytes once and hand them to every client that advertised support.
Because the encoded body is a different representation, it should have its own validator. Servers that compress at the edge commonly weaken or rewrite the ETag for this reason, and a server that returns the same strong tag for compressed and uncompressed copies can cause a range request to stitch mismatched bytes together.
Compressing an already compressed body is a real failure mode in proxy chains. An origin that gzips, in front of an edge that gzips again, produces a body with two layers where the header names one, and the client fails to decode it. If you compress in the application, tell the layer in front of you not to.
Request bodies can be encoded too, but only if the server has said it will accept that. There is no negotiation header for the request direction in wide use, so a client that compresses an upload against a server that does not expect it gets a parse failure rather than a polite refusal.
Examples
HTTP/1.1 200 OK
Content-Type: text/css
Content-Encoding: br
Vary: Accept-Encoding
Content-Length: 4123The length is the compressed size, not the size of the original stylesheet.
curl -s --compressed https://example.com/app.css | head -5The --compressed flag advertises the codings curl can decode and decompresses the response for you.
Things that catch people out
- Setting the header without actually compressing the body gives the client binary rubbish, because it will try to decode plain text as a compressed stream.
- Compressing twice in a proxy chain produces a body the client cannot read, and the error rarely names the layer that added the second pass.
- Do not confuse this with Transfer-Encoding: chunked. That describes framing for one hop and says nothing about compression.
Try it: HTTP Headers Checker
Check a live URL or paste headers you already have. It grades six security headers from A+ to F and lists every other header the response returned.
HTTP Headers Checker
LOCAL · Browser-OnlyView HTTP response headers for any URL
Enter any website URL to fetch and analyze its HTTP response headers. We'll automatically add https:// if needed.
Why Check Security Headers?
Security headers protect your website against common attacks like XSS, clickjacking, and MIME sniffing. They're set by your web server and cost nothing to implement. Missing security headers are one of the most common findings in security audits.
Related HTTP headers
All http headers →Accept-Encoding: negotiating gzip, br and zstd
Which compression tokens clients send, how identity and the wildcard behave, why the response needs Vary, and how to test whether compression is really on.
Transfer-Encoding: chunked framing on the connection
What chunked transfer encoding does, why it is a hop by hop property, why it must never accompany Content-Length, and why HTTP/2 forbids it entirely.
Vary: which request headers change the response
How Vary extends a cache key, why Vary: User-Agent destroys hit rates, what Vary: * means, and the CORS case where forgetting Vary: Origin causes real bugs.
Content-Length: the size of the body in octets
What Content-Length counts, why it must never accompany Transfer-Encoding, what happens when it disagrees with the body, and when it may be omitted.
Content-Language: the audience a document is for
What Content-Language actually states, how it differs from the lang attribute in markup, when to list several tags, and how it pairs with Accept-Language.
Content-Disposition: download prompts and file names
How to force a download instead of inline display, how filename and filename* differ, and how to send a non-ASCII file name that survives every browser.
Tools for this
- HTTP Request Builder Free online HTTP request builder - build and test HTTP requests with custom headers and body
- HTTP Headers Checker Free online HTTP headers checker - view HTTP response headers for any URL