Hreflang tags: a complete guide with examples
Hreflang tells Google that several pages are the same content for different languages or countries, so it can show a German speaker the German page and a British shopper the UK page. It's simple in principle and easy to get subtly wrong, and when it's wrong, Google quietly ignores it.
What hreflang does, and doesn't
Hreflang is an attribute on a link that says "this other URL is the version of this page for language X, optionally in country Y". Google uses it to pick which version to show in its results for each searcher.
It helps when you have:
- the same content translated into several languages;
- one language with regional variations, such as US and UK English with different prices, spelling or delivery details;
- a page that is only partly translated, such as translated navigation around the same product grid.
What it doesn't do: it doesn't raise rankings, it doesn't translate anything, and it isn't how Google works out a page's language. Google's documentation says it detects language with its own algorithms and doesn't use hreflang or the HTML lang attribute for that. Hreflang only connects versions that already exist.
It also doesn't make translated pages count as duplicates. Google treats localised versions as duplicates only when the main content is left untranslated.
How a hreflang cluster works
All versions of a page form a cluster, and two rules hold the cluster together:
- Every version lists every version, including itself. The English page lists English, German and French; so do the German and French pages.
- Every link must be returned. If the English page points to the German page, the German page must point back to the English page with exactly the same URL. Google says that if two pages don't both point to each other, the tags are ignored.
The return-link rule stops anyone from declaring themselves the "German version" of your site. In practice it means the simplest correct setup is one identical block of tags on every page of the cluster:
<link rel="alternate" hreflang="en" href="https://example.com/shoes/"> <link rel="alternate" hreflang="de" href="https://example.com/de/schuhe/"> <link rel="alternate" hreflang="fr" href="https://example.com/fr/chaussures/"> <link rel="alternate" hreflang="x-default" href="https://example.com/shoes/">
Pairs are judged one at a time. If the French page forgets to link to the German one, only that pair is ignored; English–German and English–French still work.
Language and country codes
A hreflang value is a language code from ISO 639-1, optionally followed by a hyphen and a country code from ISO 3166-1 alpha-2. A script code from ISO 15924 can sit between them for languages written in more than one script. Case doesn't matter, though countries are usually written in capitals.
| Code | Valid? | Meaning or fix |
|---|---|---|
de | Yes | German, for German speakers everywhere |
de-AT | Yes | German for Austria |
zh-Hant | Yes | Chinese in Traditional script |
en-UK | No | The UK's code is GB: use en-GB |
en_US | No | Underscores aren't allowed: use en-US |
gb, us | No | A country can't be used alone; the language always comes first |
jp, cn, dk | No | These are countries. The languages are ja, zh and da |
es-419 | No | Google doesn't support UN region numbers. Use es, or list each country |
en-EU | No | EU isn't a country code. Google says reserved codes such as EU, UN and UK have no effect |
Use a country only when that country gets a genuinely different page. If one Spanish page serves every Spanish speaker, es is right and es-ES, es-MX and so on add nothing. When you do split by country, Google recommends also giving one version the language alone, so speakers in countries you didn't list still get a match.
x-default
hreflang="x-default" names the page for everyone who matches none of your versions. It's usually one of two things:
- a language or country selector page; or
- the version you consider the global default, often the English one.
x-default is optional, but it's the cleanest way to say what happens to a Brazilian visitor on a site with only English, German and French versions. Like every other entry, it belongs in the block on every page of the cluster.
Three ways to add hreflang
Google treats the three methods as equivalent. Pick one per set of pages; using two or three gives no extra benefit and makes them harder to keep in step.
1. Link tags in the HTML head
The block shown above, inside the page's <head>. This is the most common method and the easiest to check. The tags must be in a well-formed head: an element that doesn't belong there, such as an <img> or a <div> injected by a script, ends the head early, and any hreflang tags after it are lost.
2. The HTTP Link header
For files with no HTML head, such as PDFs, the same information goes in a response header:
Link: <https://example.com/guide.pdf>; rel="alternate"; hreflang="en",
<https://example.com/de/leitfaden.pdf>; rel="alternate"; hreflang="de"
3. The XML sitemap
On large sites, adding tags to every page template can be heavy. Instead, each URL in the sitemap lists its alternates, using the xhtml namespace:
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://example.com/shoes/</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/shoes/"/>
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/schuhe/"/>
</url>
<url>
<loc>https://example.com/de/schuhe/</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/shoes/"/>
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/schuhe/"/>
</url>
</urlset>
Every version still needs its own <url> entry with the full set, including itself. The downside is visibility: nobody notices broken sitemap hreflang by looking at a page.
Hreflang with canonicals, redirects and noindex
Hreflang should only ever point to URLs Google can index and treats as canonical:
- Each version's canonical points to itself. A common mistake is canonicalising every language to the English page. That tells Google the translations are duplicates to be folded into English, which defeats the hreflang.
- No redirects. If an href redirects, use the URL it ends on. The return link from the destination won't match the redirecting URL.
- No noindex, no 404s, no robots.txt blocks. A version Google can't crawl or index can't be shown, and it can't confirm its return links.
- Exact URLs.
https://example.com/de/andhttps://www.example.com/deare different URLs to Google. Use the same protocol, host and trailing slash everywhere, and always the full URL: Google requires fully qualified URLs, includinghttps://.
WordPress, Shopify and other platforms
- WordPress: multilingual plugins such as WPML and Polylang add hreflang tags for translations they manage. Pages translated outside the plugin, or a theme that also adds tags, are where errors creep in.
- Shopify: stores selling in several languages or markets get hreflang tags generated for them. Check that every market's domain or subfolder is included and that the codes match how you actually target countries.
- Custom sites: generate the block from one shared list of versions per page, so every page outputs the same set. Hand-written tags drift out of step as pages are added.
Whatever the platform, check the output, not the settings screen.
Common mistakes
- Missing return links, usually because one version was added or moved later.
- Invalid codes, especially
en-UK, underscores and country codes used as languages. - Pointing at URLs that redirect, often the
http://or non-wwwform. - Canonical tags that point every version to one language.
- Relative URLs such as
/de/instead of full URLs. - Two different URLs given the same code.
- Tags placed in the
<body>, or after something that ends the head early.
How to test it
Because hreflang only works when pages agree with each other, checking one page isn't enough; every version has to be fetched and compared. A hreflang checker does that from a single URL: it validates each code, fetches every alternate, and shows a matrix of which page links back to which:
Run it on one page of each template, such as the homepage, a category page and a product or article page, since hreflang is usually generated per template. Search Console no longer has an international targeting report (Google retired it in 2022), so a checker is now the main way to catch errors.
Questions
What does hreflang mean?
It's the "language of the linked page" attribute (href + lang): it marks a linked URL as the version of a page for a particular language, and optionally a particular country.
What is hreflang x-default?
A special value for the page to show visitors whose language or country matches none of your versions, usually a language selector or your main international page.
Do I need hreflang if my site is in one language?
No. Hreflang is only for sites with more than one language or regional version of the same pages.
Is hreflang a directive?
Treat it as a strong signal rather than a command. Google uses it to choose between versions, but may still show a different version if the annotations are broken or the pages disagree.
Should I use hreflang or the lang attribute?
Both, for different jobs. <html lang> declares the language of the page for browsers, screen readers and translation tools; hreflang links the versions together for search engines.