The reflex when a site goes multilingual is to be helpful: read Accept-Language, look at the IP, and serve the language the visitor probably wants.
It is the wrong instinct, and the reasons compound.
One URL cannot be two pages
The entire mechanism search engines use for multilingual sites assumes a URL has one language. hreflang says "this page is the English version, and that URL is the Spanish one". canonical says "this is the address of this content".
Detection breaks the assumption underneath both. The same URL now returns English or Spanish depending on who asked, so the hreflang on it is true for one visitor and false for another. A crawler that arrives with Spanish headers indexes Spanish content at a URL declaring itself English, and the tags you added to be helpful are now actively misleading.
The reader loses too. Sharing a link becomes a gamble: the recipient may not get the page you were reading.
The caching cost is bigger than it looks
A response that varies by visitor cannot be cached and served to everyone. That means either no edge caching at all, or a Vary header that fragments the cache and mostly misses.
On a marketing site this is usually the single largest avoidable latency. The pages are static in every meaningful sense; the only thing stopping them being served from a nearby cache is a language decision made per request.
Remove the detection and the pages become byte-identical for every visitor, including any cookies they set, and the whole site can be cached at the edge. That change alone is often worth more than every other optimisation on the list.
The rule, and the escape hatch
The rule can be a domain, a path prefix, or a subdomain. What matters is that it is visible in the URL and nothing overrides it.
- Country domains carry a strong signal about market and are unambiguous to a reader. They cost a domain per market, and cookies do not cross between them.
- Path prefixes keep one domain and one authority, which is usually the pragmatic choice.
Either way, the language switcher changes the URL. It does not toggle a preference that leaves the address unchanged, because then the address has stopped describing the page again.
There is one legitimate exception, and it proves the rule: a page that genuinely belongs to a single visitor rather than to the public, such as a booking page opened from a link. There, the reader's own choice should win, it should persist, and it should travel with whatever they submit so the confirmation email is in the same language as the page. That is not detection. Nothing is being guessed; the visitor said so.
Two failures worth checking for yourself
Canonical and hreflang belong in HTML tags. Google reads them from HTTP Link headers too. Bing does not read hreflang from headers at all, and Bing backs several AI answer engines, so header-only implementations are invisible to a growing share of the traffic worth having.
Check what a crawler receives, not what your browser receives. Some frameworks stream page metadata for any user agent they do not recognise as a bot, which puts the title, description and canonical after the closing head tag where a browser will still hoist them. Their internal bot lists cover search engines and social scrapers, and are frequently missing the AI crawlers that appeared more recently. The result is a site whose robots file invites those crawlers and then serves them a page with no title.
It takes one request with a crawler's user agent to find out, and it is worth doing before assuming.
Summary
- Detection makes one URL two pages, and hreflang cannot describe that.
- A visitor-dependent response cannot be cached at the edge.
- Put the language in the URL, and make the switcher change it.
- A per-visitor preference is fine where the page belongs to that visitor, and it should travel with what they submit.
- Emit canonical and hreflang as tags, and verify what a crawler actually gets.



