Content negotiation

HTTP letting the server choose a language or format from request headers, such as Accept-Language or Accept, before sending the response.

server picks which version to sendsame URL different response formatchoose JSON or HTML from the requestserve the browser's preferred languagethe site opened in German and I never askedwhy the response changes by request headerhow does a site know what language I wantAccept header handlingcontent negotation

What it is

Content negotiation is HTTP's mechanism for choosing one representation of a resource from request headers. A client can rank media types with Accept, languages with Accept-Language, and encodings with Accept-Encoding; the server selects a variant it supports and describes what it sent with headers such as Content-Type and Content-Language.

Reach for it when one endpoint genuinely serves alternate formats, such as HTML and JSON, or when an unlocalized first visit needs a language guess. Parse quality weights and wildcards instead of taking the first token: a real header looks like 'fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5', and the highest q value that you actually ship wins. For language, an explicit locale URL or saved user choice should beat a negotiated guess.

Gotcha: caches cannot see the decision unless the response names every request header that changed it in Vary. Forget 'Vary: Accept-Language' and a CDN may cache French for the next English visitor. Negotiating language forever on one URL also makes sharing, indexing, and user overrides harder, so negotiate once and redirect to a stable locale URL when the product has localized routes.

Ask AI for it

Add HTTP content negotiation to this endpoint using RFC 9110 semantics. Parse Accept media ranges, q values, specificity, and wildcards; choose between application/json and text/html; and return 406 Not Acceptable when no supported representation matches. For the unlocalized entry route only, parse Accept-Language with BCP 47 matching and redirect to the chosen locale URL. Set Content-Type and Content-Language on the response, add every decision header to Vary, and add cache tests proving one negotiated variant cannot be served to a different request.

You might have meant

language negotiationlocalelocale routinglocale fallback chainvary header

Go deeper