How HTTP Works

Request header

> Accept-Encoding: gzip, br;q=0.9

Accept-Encoding Header

Learn how Accept-Encoding tells servers which compression formats (gzip, br, deflate) your client supports to reduce bandwidth and speed up page loads.

Reviewed 3 min readbeginner2 sourcesTry itMarkdown
Direction
Request
Category
Content negotiation
Spec
RFC 9110 §12.5.3
JS can set it
No: forbidden header name
On this page

TL;DR: Accept-Encoding is the request header where a client lists the compression formats it can decode, such as gzip or br (Brotli). The server picks one, or none, and says which in Content-Encoding. Browsers set it for you and JavaScript can’t change it, so test with curl.

What is Accept-Encoding?

In a request, this field negotiates content codings. It’s separate from Transfer-Encoding, which frames an HTTP/1.1 message. Servers can send Accept-Encoding too, to advertise which codings they accept in request bodies, for example in a 415 response. MDN describes both uses.

How Accept-Encoding Works

Here’s a request and response with bodies omitted. Headers and outputs on this page are trimmed examples.

GET /report HTTP/1.1
Host: example.com
Accept-Encoding: gzip, br;q=0.8
HTTP/1.1 200 OK
Content-Type: application/json
Content-Encoding: gzip
Vary: Accept-Encoding

No Content-Encoding in the response means the body wasn’t compressed. That’s allowed: offering gzip doesn’t force the server to use it.

Common Compression Algorithms

gzip is gzip and br is Brotli. HTTP’s deflate is the odd one: it means a zlib wrapper around a DEFLATE stream, not raw DEFLATE. Only advertise formats your client can decode. For curl, curl --version lists what your build supports.

Quality Values and Preferences

Accept-Encoding: br;q=1, gzip;q=0.8

This says “Brotli preferred, gzip fine”. Plain br, gzip gives both the default quality of 1, because list order isn’t a ranking.

Real-World Examples

Let curl advertise what it supports and decode the response for you:

curl --compressed -D - -o /dev/null https://example.com/

--compressed decodes the body, but the printed headers still describe the encoded response. So the saved file’s size won’t match Content-Length, which counts compressed bytes.

Compression Effectiveness

How much you save depends on the content. There’s no fixed ratio for HTML, JSON or JavaScript. Measure the same resource both ways and check which coding the server actually chose before crediting compression with the difference.

Responses that arrive already encoded are a good diagnostic case. If the application sends Content-Encoding: gzip, look at the raw bytes saved without --compressed (the commands in the measuring section below save them to /tmp/gzip.body):

file /tmp/gzip.body
gzip -t /tmp/gzip.body

Run the gzip check only after the saved headers confirm the coding. A 200 status says nothing about whether the body is valid gzip, and a gzip failure on a body that was never encoded tells you nothing about negotiation.

Getting Accept-Encoding right

Inside an nginx http, server, or location block:

gzip on;
gzip_types text/plain application/json text/css application/javascript;
gzip_vary on;

The nginx gzip module always compresses text/html on top of whatever gzip_types lists. Both gzip and gzip_vary default to off, so you need to turn them on. This config gives you gzip only, not Brotli.

In browsers, Accept-Encoding is a forbidden request header. Leave it and Content-Length out of fetch() calls; the browser manages both.

For Caddy serving files from /srv/www, turn on its encoders directly:

example.com {
    root * /srv/www
    encode zstd gzip
    file_server
}

Caddy’s encode directive negotiates these formats from the request. Putting zstd first makes it the server’s pick when the client doesn’t express a stronger preference. A client that only offers gzip gets gzip.

Measure the savings on your own responses

Swap in the URL you’re investigating. These requests save the raw bodies, with no automatic decompression from curl:

curl -sS -D /tmp/identity.headers -o /tmp/identity.body \
  -H 'Accept-Encoding: identity' https://example.com/
curl -sS -D /tmp/gzip.headers -o /tmp/gzip.body \
  -H 'Accept-Encoding: gzip' https://example.com/
cat /tmp/identity.headers /tmp/gzip.headers
wc -c /tmp/identity.body /tmp/gzip.body

Compare Content-Encoding, status and validators like ETag across both responses. Matching byte counts alone don’t prove the server ignored the header.

Compression Priority and Quality Values

Under RFC 9110 §12.5.3, a request with no Accept-Encoding field accepts any coding, while an empty field asks for no coding at all. identity means “no encoding”. It’s acceptable by default unless you exclude it with identity;q=0, or with *;q=0 when there’s no more specific entry for identity.

Accept-Encoding: identity asks for an uncompressed response. Because gzip and Brotli aren’t listed, they aren’t acceptable, and a server that sends gzip anyway is ignoring the request. Test this case when an intermediary seems to compress every response.

Frequently asked questions

What is Accept-Encoding?

Accept-Encoding tells the server which compression algorithms the client supports. Common values are gzip, deflate, and br (Brotli). Servers use this to compress responses.

What compression should I accept?

Accept only content codings your client can decode. Browser-managed values vary by browser and connection; inspect the actual request instead of copying a fixed list.

What does Accept-Encoding: identity mean?

identity means no content encoding. Accept-Encoding: identity requests an unencoded response and does not make gzip or Brotli acceptable.

How does Accept-Encoding affect caching?

Servers should include Vary: Accept-Encoding so caches store different versions for different encodings. This prevents serving gzip to clients that cannot decompress.

Sources

  1. MDN Web Docs: Accept-Encodingdeveloper.mozilla.org
  2. RFC 9110: Accept-Encodingrfc-editor.org

Keep going

Browse /search