The multilingual bugs that never throw: hreflang, JSON-LD and a site in 12 languages
I run a search engine that publishes in twelve languages from one static site on Cloudflare Pages. Last week I audited its machine-readable layer — the part crawlers and answer engines read rather than humans — and found four problems. None of them threw an error. None appeared in logs. Every page rendered perfectly. That is the whole point of this post: the multilingual layer fails in a register where nothing tells you. 1. The homepage was serving the wrong language to everyone abroad The site's primary market speaks Hebrew, so / is Hebrew and /en/ , /ar/ , /de/ and nine others sit alongside it. A middleware rule redirected visitors from one specific region to their language. Everyone else — including every English speaker on earth — landed on Hebrew. My first instinct was to fix it with a broader geo-redirect: detect English-speaking countries, send them to /en/ . This would have been a bad idea, and it is worth saying why. Googlebot crawls predominantly from US IPs. A geo-redirect on / that keys off country would take the crawler off the Hebrew homepage and onto the English one almost every time it visited. You do not want your primary-market homepage to become the page the crawler can never reach. The correct tool is hreflang , and it is what search engines built for exactly this. Checking the page, the tags were already there and already right: <link rel= "alternate" hreflang= "he" href= "https://example.com/" > <link rel= "alternate" hreflang= "en" href= "https://example.com/en/" > <link rel= "alternate" hreflang= "ar" href= "https://example.com/ar/" > <!-- …ten more… --> <link rel= "alternate" hreflang= "x-default" href= "https://example.com/en/" > Two things make this work, and both are easy to get wrong: The set must be reciprocal. Every page in the group lists every other page including itself . If /en/ does not point back at / , search engines are entitled to ignore the whole cluster. x-default is not "the default language" — it is the fallback for users