How clients say what they can accept
Proactive content negotiation lets a client tell the server which formats,
compression schemes and languages it prefers, and the server picks the best match.
This reference covers the four Accept-family headers, the q-value weighting
syntax they share, and the wildcard precedence rules — plus a parser that sorts
any header by preference.
The four header families
| Header | Negotiates | Server responds with |
|---|---|---|
Accept | MIME type / media type | Content-Type |
Accept-Encoding | Content coding (gzip, br, zstd) | Content-Encoding |
Accept-Language | Natural language / locale | Content-Language |
Accept-Charset | Character set (deprecated) | Content-Type; charset= |
How q-values work
Each header is a comma-separated list of values, each optionally carrying a
quality factor with ;q=:
Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
Accept-Encoding: br;q=1.0, gzip;q=0.8, *;q=0.1
Accept-Language: en-GB, en;q=0.7, fr;q=0.3
The server scores every value it can produce by the client’s q (default 1),
breaking ties by specificity (text/html beats text/* beats */*). A value
with q=0 is explicitly refused. The chosen variant is reflected back — in
Content-Type, Content-Encoding or Content-Language — and the response
should carry a matching Vary header so caches key correctly.
Parsing example
Given this Accept header:
Accept: text/html;q=0.9, application/json, */*;q=0.1
The parser ranks:
application/json— q=1.0 (default), specific typetext/html— q=0.9*/*— q=0.1
A server that can serve both JSON and HTML will choose JSON because it carries the higher q. If the server can only serve HTML, it falls back to that.
Wildcard precedence rule
When two values have the same q, the more specific one wins:
text/html (specific) > text/* (subtype wildcard) > */* (full wildcard).
This matters when building middleware: a */*;q=1.0 in a client header does not
automatically make every type equally preferred — an explicit text/html;q=0.8
still outranks the wildcard’s 0.8 because of its specificity.
Practical notes for API developers
- Default q is
1; only add;q=when you need a non-default preference — an explicitq=1.0is harmless but adds noise. q=0is a hard reject — useful for opting out of a specific encoding (for example,gzip;q=0to prevent gzip even when a wildcard*is present).- Any response that varies by an
Accept-family header must include aVaryheader listing it, or caches will serve the wrong variant to different clients. Accept-Charsetis effectively dead: assume UTF-8 everywhere and skip it for new APIs.