Hreflang for Multilingual Sites

Hreflang has a well-earned reputation: the concept fits in one sentence, and the implementation fails on most sites that attempt it. The sentence is this — hreflang tells search engines which language and regional versions of a page belong together, so each user gets the right one. The failure rate comes from the details: invalid codes, missing return links, tags pointing at redirects, and plugins that quietly generate all three problems at once.

If your German customers keep landing on your English pages, or Google shows your US prices to UK visitors, this is the machinery involved. Here is how it actually works, with the exact rules and the audit checklist.

What hreflang does — and what it doesn't

Hreflang is a clustering hint, not a ranking spell. When implemented correctly, Google groups your language versions into a set and swaps in the appropriate URL for each searcher's language and location. The pages effectively share their signals within the cluster — your strong English page can help its new French sibling appear for French searchers.

What it does not do:

  • It does not boost rankings. A correct implementation gets the right version shown, not a better position.
  • It does not translate anything or fix thin translations. A machine-translated page with hreflang is still a machine-translated page.
  • It does not force geo-redirects. In fact, aggressively redirecting users by IP fights against hreflang and against Googlebot, which mostly crawls from US IP addresses. Suggest, with a dismissible banner; don't force.
  • It is not required for a single-language site serving multiple countries. One English page for the whole world needs no hreflang at all.

The syntax: language, then region, and no improvising

An hreflang value is a language code, optionally followed by a region code, joined by a hyphen:

  • Language: ISO 639-1, two lowercase letters — en, de, fr, es, nl, hu.
  • Region (optional): ISO 3166-1 Alpha-2, two letters — US, GB, DE, BE, MX. Capitalization is conventional, not required.

So en means English anywhere, en-GB means English for the United Kingdom, es-MX means Spanish for Mexico. Language alone is valid. Region alone is not — you cannot target "everyone in Belgium" with a single tag; you would use nl-BE and fr-BE.

The classic code mistakes, all of which fail silently or misfire:

  • en-UK — invalid. The United Kingdom's ISO code is GB, and this single wrong guess is probably the most common hreflang error in existence. Use en-GB.
  • en-EU — invalid. The EU is not an ISO region; there is no code for "Europe". You either list countries individually or use plain en.
  • Swapped order like GB-en — invalid. Language first, always.
  • Made-up combinations like es-LA for Latin America — LA is the code for Laos. Awkward.
  • For Chinese, prefer script codes: zh-Hans (Simplified) and zh-Hant (Traditional) describe what readers actually need better than country codes do.

Rule of thumb: if you did not copy the code from an ISO table, assume it is wrong until checked. Two minutes of verification saves a quarter of debugging.

A worked example: one page, four versions

Say your pricing page exists in US English, UK English, German, and French, and you want everyone else to get a language-neutral chooser. Every one of those four pages (plus the chooser) carries the same complete set of annotations in its <head>:

  • <link rel="alternate" hreflang="en-US" href="https://example.com/en-us/pricing/" />
  • <link rel="alternate" hreflang="en-GB" href="https://example.com/en-gb/pricing/" />
  • <link rel="alternate" hreflang="de" href="https://example.com/de/preise/" />
  • <link rel="alternate" hreflang="fr" href="https://example.com/fr/tarifs/" />
  • <link rel="alternate" hreflang="x-default" href="https://example.com/pricing/" />

Three details that trip people up in exactly this example:

  1. Every page includes a reference to itself. The German page's tag set still contains the de line pointing at the German page. Self-reference is required, not optional decoration.
  2. URLs are absolute, protocol and all. Relative URLs in hreflang are a gamble that tends to lose.
  3. German and French are language-only because there is one German version for all German speakers. Only English is split by region here — because prices differ. Do not invent regional variants you do not have.

The reciprocity rule: where most implementations die

Hreflang annotations must be mutual. If the English page claims the German page as its de alternate, the German page must claim the English page back as its en-US alternate — the so-called return link. No return link, and Google ignores the pair. Not penalizes: ignores. Which is worse in a way, because everything looks fine and nothing works.

Return-link failures rarely come from laziness. They come from asymmetry:

  • A page was translated into German but the template only updated on the English side.
  • One language version got a new URL and the others still point at the old one.
  • A page exists in five languages but was noindexed in two — a noindexed page cannot participate in a cluster, breaking the set for its siblings.
  • The canonical tag on a language version points somewhere other than itself. Hreflang must point at canonical, indexable, 200-status URLs. Hreflang to a redirect, a 404, or a canonicalized-away URL is a dead annotation.

That last rule is worth engraving somewhere: self-referencing canonical, indexable, returns 200. Check those three properties for every URL in every hreflang set and you have eliminated the majority of real-world failures.

x-default: the fallback everyone misconfigures

x-default declares the page to show searchers who match none of your specified languages and regions. A Japanese searcher hitting the example above gets the x-default URL.

Two sensible patterns:

  • Point it at a language selector page if you have one and it is a genuinely useful page (not a bare list of flag icons with no content).
  • Point it at your primary language version — usually the global English page. This is the right call for most small and mid-size sites, and it is completely fine for x-default to point at the same URL as your en tag.

What not to do: omit it (unmatched users get whatever Google guesses), or point it at a geo-redirecting URL (see above — Googlebot crawls mostly from the US and will be bounced like everyone else).

Do you even need regional variants? A decision rule

The most effective hreflang simplification is having less of it. Splitting by region multiplies your content maintenance and your annotation surface, so earn it:

  • Split by region only when the pages genuinely differ: different currency and prices, different legal terms, different product availability, materially different spelling and vocabulary. en-US vs en-GB pages that differ only in a currency symbol are usually still worth splitting for commerce; identical blog posts are not.
  • Default to language-only tags (de, not de-DE plus de-AT plus de-CH) until a concrete business reason forces the split. Every additional variant is another page to translate, maintain, and keep reciprocal — and a language-only tag already covers all those regions.
  • A useful rule of thumb: if you cannot name the specific content difference between two regional variants in one sentence, merge them.

Head tags, sitemap, or HTTP headers?

There are three delivery mechanisms, and you must pick one per page type — duplicating across methods invites contradictions.

MethodBest forWatch out for
HTML link tags in the headMost sites; what WordPress plugins generateBloats the head when you have many locales — 20 languages means 21 link tags on every page
XML sitemap annotationsLarge sites, many locales, or when you cannot edit templatesOut of sight, out of mind; regenerate on every URL change
HTTP headersNon-HTML files like PDFsThe only option for documents; rarely needed otherwise

For a WordPress site with two to six languages, head tags via your multilingual plugin are the standard answer. Past roughly ten locales, sitemap annotations keep your pages lighter and your sanity intact.

WordPress specifics: trust, but audit

WPML, Polylang, and TranslatePress all generate hreflang automatically, and they mostly get it right. Mostly. Your audit checklist after any multilingual setup — and again after major plugin updates:

  1. View source on one page per language and confirm the full tag set appears, identical across all versions, self-reference included.
  2. Check the codes the plugin chose. Plugins ask you to pick locales during setup, and a human picked en-UK from a dropdown somewhere. Verify against the ISO tables.
  3. Check canonicals do not fight hreflang. Each language version should canonicalize to itself. A stray setting that canonicalizes translations to the original language silently dissolves the whole cluster.
  4. Crawl the site with a tool that validates hreflang (Screaming Frog and similar crawlers flag missing return links, non-200 targets, and invalid codes). Fix everything in the report; partial hreflang is barely better than none.
  5. Spot-check untranslated pages. When a post exists in only one language, no hreflang set should reference a translation that is not there. Some configurations point every language's tag at the original as a fallback — which tells Google your German alternate is an English page. Turn that off.

How long until it works, and how to tell

Expect weeks, not days. Google has to recrawl every member of a cluster to confirm reciprocity, and on a modest site that takes two to six weeks after tags go live. Signs it is working: impressions in Search Console rising for the correct country properties, localized pages appearing in their own markets' results, and a decline in the wrong-language version showing up in country-specific searches. Sign it is not: everything unchanged after two months — go back to the audit checklist, because with hreflang, silent failure is the default failure mode.

The short version

Language code from ISO 639-1, region from ISO 3166-1, language first. Every page in a cluster lists every version including itself, with absolute URLs, all pointing at canonical indexable 200s. Add an x-default. Split by region only when content genuinely differs. Pick one delivery method. Then crawl and verify, because the plugin's checkbox and reality are two different claims — and hreflang only rewards the sites that check.

Photo: Jonathan Borba on Pexels