Glossary Term
Content Negotiation
Content negotiation lets one URL serve different formats, languages or encodings based on Accept headers. See q-values, Vary, 406 and the caching traps.
TL;DR: Content negotiation is one URL, several representations. The client states preferences with
Accept,Accept-LanguageandAccept-Encoding; the server picks one and must list the headers it used inVary.
Content negotiation is the HTTP mechanism for choosing among multiple representations of the same resource. In the common server-driven form, the client sends preference headers and the server selects a format, language or encoding, then labels the choice with Content-Type, Content-Language or Content-Encoding.
An example
GET /reports/42 HTTP/1.1
Host: api.example.com
Accept: application/json, text/csv;q=0.5, */*;q=0.1
Accept-Language: de-CH, de;q=0.9, en;q=0.5
Accept-Encoding: br, gzip
HTTP/1.1 200 OK
Content-Type: application/json
Content-Language: de
Content-Encoding: br
Vary: Accept, Accept-Language, Accept-Encoding
How the choice is made
- Each header lists options with optional quality values from 0 to 1. No
qmeans 1;q=0means “never”. - More specific ranges beat less specific ones regardless of order.
text/html;level=1overridestext/html, which overridestext/*, which overrides*/*. Accept-Encodingis the one negotiation that every site does, and compression is applied after the representation is chosen.
Non-obvious facts
Varyis not optional. A CDN or browser that caches a negotiated response withoutVarywill serve the wrong variant to the next user. The reverse,Vary: User-AgentorVary: Cookie, fragments the cache into near-useless pieces; normalize the header at the edge or negotiate on something narrower.- 406 is rarely what you want. RFC 9110 allows the server to send a default representation instead of a 406, and most do. Browsers send
*/*anyway, so a 406 mostly appears on API endpoints with a strictAccept. - A file extension or query parameter is often better for caches.
/reports/42.csvis cacheable, linkable and easy to test withcurl, whileAcceptnegotiation is invisible in the URL. - Languages are a bad place for surprises. Redirecting by
Accept-Languagealone breaks sharing and crawling; many sites offer a language switcher and treat the header as a hint. - Request bodies have the mirror image. A client’s
Content-Typethat the server does not accept yields415 Unsupported Media Type, not 406.
Go deeper
- Accept header
- Accept-Language header
- Accept-Encoding header
- Vary header
- 406 Not Acceptable
- Content negotiation guide: how servers pick a representation, real server examples, and CDN caching.
Frequently asked questions
What is content negotiation in HTTP?
It is the mechanism by which a client and server pick the best representation of a resource, such as JSON or HTML, English or German, gzip or Brotli, for the same URL.
What does q=0.8 mean in an Accept header?
It is a quality value between 0 and 1 that ranks a preference. Types without q default to 1, and q=0 means not acceptable.
When should a server return 406?
When it can only produce representations the client excluded. In practice most servers ignore an unsatisfiable Accept and send a default, because a 406 is rarely more useful to the client.
Why must negotiated responses send Vary?
Because caches key on the URL by default. Vary tells a cache which request headers influenced the response, so it does not serve the German page to an English reader.
Sources
Related
Accept Header
Learn how the Accept header tells servers which content types (JSON, HTML, XML) your client can handle. Master content negotiation and quality values.
Accept-Language Header
Learn how the Accept-Language header tells servers which languages your client prefers for localized content. Understand language tags and quality values.
Vary Header: Cache Keys, Vary: Origin and Accept-Encoding
Vary lists the request headers a response depends on, so caches keep separate copies. Vary: Accept-Encoding, Vary: Origin for CORS, Vary: *, and CDN cache keys.
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.