Accept-Language: language negotiation and its limits
Accept-Language lists the natural languages a visitor prefers, with quality values, so a server can pick which translated version of a page to return.
At a glance
- Direction
- Request only. The response describes what it sent with Content-Language.
- Defined in
- RFC 9110, with language tags from RFC 5646
- When absent
- No preference was expressed, so serve your default language rather than guessing from the address.
- Tag format
- A base language, optionally with a region: en, en-GB, pt-BR, zh-Hant
- Matching
- Fall back from en-GB to en before giving up; never require an exact match.
- Privacy
- An unusual language list is a strong fingerprinting signal, so browsers have trimmed it.
- Response pair
- Content-Language, plus Vary: Accept-Language if the body changes
In detail
The header is an ordered preference list, not an instruction. A visitor sending en-GB, en;q=0.9, fr;q=0.8 would like British English, will accept any English, and can read French at a push. A server should walk that list in order, falling back from a region specific tag to its base language, and only then to its own default.
Language is not location. A traveller, an expatriate or anyone using a borrowed device sends a language that says nothing about where they are or what currency they hold, and browsers do not send a country at all. Using this header to pick a price, a tax rate or a shipping region produces confident, wrong answers.
Automatic redirection based on the header is the classic mistake. It makes a shared link open differently for different people, hides content from search engines that crawl with one language, and traps anyone whose device language is not the language they read. Negotiate the default, show a visible switch, and remember the explicit choice.
Because the list can be fairly distinctive, browsers have been reducing what they send: many now transmit only the primary language, or a shortened list, in a deliberate move to cut the fingerprinting surface. Design your matching so that a single tag with no region still resolves to a sensible page.
Examples
Accept-Language: en-GB, en;q=0.9, fr;q=0.8, *;q=0.5HTTP/1.1 200 OK
Content-Language: en-GB
Vary: Accept-Language
Content-Type: text/html; charset=utf-8Things that catch people out
- Requiring an exact tag match fails a large share of real traffic. A request for en-GB should be satisfied by an en page rather than falling through to your default.
- Redirecting on this header without a visible language switch strands anyone whose device language is not the language they want to read.
- Serving different bodies without Vary: Accept-Language lets a cache hand one visitor's language to the next visitor.
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-Language: the audience a document is for
What Content-Language actually states, how it differs from the lang attribute in markup, when to list several tags, and how it pairs with Accept-Language.
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.
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.
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.
Content-Length: the size of the body in octets
What Content-Length counts, why it must never accompany Transfer-Encoding, what happens when it disagrees with the body, and when it may be omitted.
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.
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