Accept-Encoding: negotiating gzip, br and zstd
Accept-Encoding lists the content codings a client can decode, such as gzip, br or zstd, so the server can compress the body it sends back.
At a glance
- Direction
- Request only. The server answers with Content-Encoding when it compresses.
- Defined in
- RFC 9110
- When absent
- Any encoding is acceptable in principle, but a careful server sends the body uncompressed.
- Common tokens
- gzip, br for Brotli, zstd, deflate, identity, and the wildcard *
- identity
- No transformation. An empty field value means only identity is acceptable.
- Response pair
- Content-Encoding on the response, plus Vary: Accept-Encoding
- Not to be confused with
- Transfer-Encoding, which is about the connection rather than the payload
In detail
Compression is negotiated because the client has to be able to decode what it receives. Browsers advertise gzip and Brotli everywhere and increasingly zstd, so the practical question for a server is which of the offered codings gives the best ratio for the cost. Brotli usually wins on text at rest, gzip is cheaper to produce on the fly, and neither is worth applying to an already compressed image or video.
Quality values work here as they do on Accept, and q=0 is a refusal. A client can say gzip;q=1.0, identity;q=0 to insist on compression, though almost nothing does. Sending an empty field value is the way to say that only identity is acceptable, which is a different statement from omitting the header entirely.
The response must then carry Content-Encoding naming what was applied, and Vary: Accept-Encoding so caches keep the compressed and uncompressed copies apart. Missing the Vary line is a genuine corruption bug rather than a slow path: a shared cache can hand compressed bytes to a client that never asked for them.
Compressing responses that reflect user input alongside secrets has a known risk, since the compressed size leaks information about how much the two have in common. It is the mechanism behind several published attacks on cookies in compressed responses, and it is the reason some APIs deliberately disable compression on authenticated endpoints.
Examples
Accept-Encoding: gzip, deflate, br, zstdcurl -sI -H 'Accept-Encoding: gzip, br' https://example.com/app.js | grep -i 'content-encoding\|vary'You want to see both a Content-Encoding line and a Vary line mentioning Accept-Encoding.
Accept-Encoding: identityThings that catch people out
- Serving a compressed body without Vary: Accept-Encoding lets a shared cache deliver those bytes to a client that cannot decode them.
- Compressing images, video and archives wastes processor time and usually makes the payload slightly larger.
- The deflate token has been implemented inconsistently for years. Offer gzip or Brotli instead rather than relying on it.
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 →Content-Encoding: what compression was applied
What Content-Encoding declares, how it differs from Transfer-Encoding, why it changes the ETag, and how double compression happens in a proxy chain.
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.
Accept: asking for a media type, with preferences
How the Accept header expresses preferences with q values, how servers pick a representation, and what to return when nothing on the list can be produced.
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.
Accept-Language: language negotiation and its limits
How Accept-Language ranks languages, why matching should fall back from a region to a base tag, and why it is a poor way to pick a currency or a country.
Content-Type: media type, charset and boundary
How Content-Type is structured, why the charset parameter still matters, what boundary does on a multipart upload, and how a wrong type breaks a page.
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