Hreflang tells Google which language and region version of a page to surface to which user. When it’s wrong, Google falls back to its own guess — usually serving the English version to non-English searchers, or the US version to EU users. The pages are still indexed; they just rank for the wrong queries in the wrong markets.
Why it matters
Hreflang is a clustering signal. If the cluster is malformed, Google doesn’t penalize — it ignores the hreflang entirely and picks a canonical version on its own. You end up with example.com/de/ competing against example.com/ for German users instead of being served in their place.
The four mistakes that account for most broken hreflang clusters:
- Missing return tags. Page A references page B; page B doesn’t reference page A. Google requires bidirectional confirmation.
- Wrong language codes. ISO 639-1 only.
en-ukis invalid (it’sen-gb).cnis invalid (it’szh). - Region without language. Hreflang values must always include a language.
hreflang="us"is invalid; usehreflang="en-us". - Pointing to non-200 URLs. Targets that redirect, 404, or canonicalize elsewhere are silently dropped from the cluster.
How to detect it
Inspect the raw HTML or response headers — not the rendered DOM, since some crawlers don’t execute JS:
curl -s https://example.com/de/ | grep -i 'hreflang'
Then verify reciprocity. For every URL in the set, every other URL in the set must reference it back, including a self-reference:
<link rel="alternate" hreflang="en" href="https://example.com/" />
<link rel="alternate" hreflang="de" href="https://example.com/de/" />
<link rel="alternate" hreflang="fr" href="https://example.com/fr/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/" />
The same four tags must appear on the English, German, AND French pages. Each page references the full cluster, including itself.
Google Search Console → Legacy tools → International Targeting reports cluster errors after crawl, but the report is rate-limited and lags by days. For a live audit, hreflang.org or any cluster validator gives instant reciprocity checks.
The fix
Universal HTML — in <head>
<link rel="alternate" hreflang="en" href="https://example.com/" />
<link rel="alternate" hreflang="en-gb" href="https://example.com/uk/" />
<link rel="alternate" hreflang="de" href="https://example.com/de/" />
<link rel="alternate" hreflang="de-at" href="https://example.com/at/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/" />
Rules:
- Use ISO 639-1 language codes (
en,de,fr,zh) and ISO 3166-1 Alpha 2 region codes (gb,us,de,at). - Always pair region with language:
en-gb, nevergbalone. - Include
x-defaultfor the fallback when no language matches. - Absolute URLs only.
HTTP header — for non-HTML resources (PDFs, etc.)
Link: <https://example.com/doc-en.pdf>; rel="alternate"; hreflang="en",
<https://example.com/doc-de.pdf>; rel="alternate"; hreflang="de"
XML sitemap — at scale
For sites with hundreds of localized URLs, the sitemap-based approach scales better than per-page tags:
<url>
<loc>https://example.com/</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/" />
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/" />
</url>
<url>
<loc>https://example.com/de/</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/" />
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/" />
</url>
Pick one method per cluster. Mixing tag-based and sitemap-based for the same URLs creates conflicting signals.
WordPress
WPML and Polylang both emit hreflang automatically once languages are configured. Yoast SEO Multilingual handles reciprocity by reading the translation graph. Verify the output — manual overrides in custom themes are the usual source of broken clusters.
Next.js (App Router)
export async function generateMetadata({ params }: Props): Promise<Metadata> {
return {
alternates: {
languages: {
"en": "https://example.com/",
"de": "https://example.com/de/",
"fr": "https://example.com/fr/",
"x-default": "https://example.com/",
},
},
};
}
Common pitfalls
en-ukis wrong. The country code for the United Kingdom isgb, notuk. This is the single most common hreflang bug.zhvszh-cnvszh-tw. Usezh-cn(Simplified) andzh-tw(Traditional) — plainzhis ambiguous.- Pointing the cluster at canonical URLs that point elsewhere. If
/de/has<link rel="canonical" href="https://example.com/">, Google drops the German URL from the cluster entirely. - Forgetting the self-reference. Each page in the cluster must reference itself with its own hreflang.
- Adding hreflang to noindexed pages. Google ignores hreflang signals from non-indexable URLs.