Hreflang Tags: The Complete Setup Guide (With the Return-Link Mistake Everyone Makes)
Hreflang only works in pairs: if the page you point to doesn't point back, Google ignores both tags. Here's the syntax, the codes that fail silently, and three ways to implement it.
The short answer
Hreflang is an attribute on a <link rel="alternate"> tag that tells Google which URL is the version of a page for a given language or region. Every version carries the same block: one tag per version, including itself, plus an optional x-default fallback. Values are an ISO 639-1 language code (de), optionally followed by an ISO 3166-1 alpha-2 region (en-gb), and every URL must be absolute. The rule that breaks most setups is reciprocity: if page A lists page B and B doesn't list A back, Google ignores the pair.
What hreflang is used for
Hreflang doesn't detect language — Google does that with its own algorithms and doesn't use hreflang or the HTML lang attribute for it. Hreflang tells Google that several URLs are localized versions of the same content, so it can show a London searcher the UK page and a German speaker the German one. It matters most for same-language regional pages, such as US and UK versions that differ only in currency and spelling and otherwise look like duplicate content. It is a signal, not a command: Google can still show a different version if it judges that better for the searcher.
The syntax, and where it goes
A pricing page with US English, UK English and German versions puts this identical block in the <head> of all three:
<!-- The same block goes in the <head> of all three versions -->
<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/pricing/" />
<link rel="alternate" hreflang="x-default"
href="https://example.com/en-us/pricing/" />Google's rules: the tags must sit inside a well-formed <head>, each href must be fully qualified (https://example.com/de/pricing/, never /de/pricing/), and hreflang shouldn't share a tag with attributes such as media. Alternates can live on other domains. The Hreflang Tag Generator builds this block, or the sitemap version, from rows of language, region and URL.
The return-link mistake everyone makes
Google's documentation is blunt: if two pages don't both point to each other, the tags are ignored. That stops another site from declaring itself the French version of your page. So when the German page lists the UK page but the UK page doesn't list the German one, Google drops that pair with no visible error. Missing return links are the first mistake Google's own documentation lists, and they usually creep in one of three ways:
- A new language is added on one side only. The new Spanish page gets the full block, but the English and German templates are never updated to list it.
- The return link points at a slightly different URL —
http://instead ofhttps://,wwwversus the bare domain, a missing trailing slash. That's a link to a different URL, not back to the page. - Tags only exist on the home page. Hreflang is page-level: every localized page needs its own block listing its own equivalents.
The consolation: Google still uses the pairs that do point to each other, so one missing return link breaks that pair, not the whole set.
Language and region codes that fail silently
- Region on its own. The first code is always read as a language, so
bemeans Belarusian, not Belgium. Usenl-beorfr-be. en-ukinstead ofen-gb. The UK's ISO code is GB. UK is a reserved code, and Google says it ignores that part of the annotation.es-laores-419for Latin America. LA is Laos, and Google explicitly listses-419as unsupported. Use country codes such ases-mx, or plaines.- Country codes as languages. Japanese is
ja, notjp;ukalone is Ukrainian. - Chinese. Google supports ISO 15924 script codes, so
zh-Hant(Traditional) andzh-Hans(Simplified) say what you mean directly. A region such aszh-twis also valid.
What x-default is for
x-default catches visitors whose language settings match none of your versions — a Japanese speaker on a site with only English and German pages. Google recommends it especially for language-selector pages and for home pages that redirect by language, but it can point at any page; the example above falls back to the US version. It's optional and belongs in the block on every version like any other entry.
Paste a URL into CheckSEO's Hreflang Validator to list every hreflang tag on the page and flag a missing self-reference, one code pointing at two URLs, malformed values like en_US, and a missing x-default. No signup.
Validate a page's hreflang tagsCanonical vs hreflang: how they work together
This is the question behind most hreflang bugs. The two tags do different jobs. Canonical picks one URL out of a group of duplicates. Hreflang tells Google that several different URLs are alternates of each other for different audiences. They are not alternatives to one another, and a localized site normally needs both.
- Each version canonicalizes to itself. The German page's canonical is the German URL. The example below shows it. A canonical on the German page pointing to the English one tells Google the German page is a duplicate to be folded away, which defeats the reason you built it. Google's duplicate-content guidance says translated pages are only treated as duplicates when the main content is left untranslated.
- Hreflang URLs must be the canonical ones. Use the final HTTPS URL that returns 200. Google says not to list HTTP versions in hreflang, and a URL that redirects or carries noindex has no usable page to hold its return tag. Skip URLs blocked in robots.txt too, because Google cannot read their tags.
- Same-language regional pages need both. For near-identical US and UK English pages, Google advises picking a preferred version and using canonical and hreflang together. If the two pages really are identical, canonicalizing one to the other and keeping only one hreflang entry is a valid choice. If you want both to exist in results, give each its own self-canonical and list both in hreflang, and expect Google to sometimes fold them together anyway when the content is the same.
- Do not mix signals. Page A that lists B as an alternate but canonicalizes to C sends conflicting instructions. A canonical is a hint that Google may override, and so is hreflang. When they disagree you cannot predict which one wins.
To see what Google actually decided, run a URL through URL Inspection in Search Console and compare the user-declared canonical with the Google-selected one. The Canonical URL Analyzer checks the declared side, including protocol, www and trailing-slash mismatches.
A worked example: English, German and French
A site has a pricing page in three languages, with English as the fallback. Each page carries the same four hreflang lines (itself, the other two languages and x-default), plus its own self-referencing canonical:
<!-- https://example.com/en/pricing/ (English, also the fallback) -->
<link rel="canonical" href="https://example.com/en/pricing/" />
<link rel="alternate" hreflang="en" href="https://example.com/en/pricing/" />
<link rel="alternate" hreflang="de" href="https://example.com/de/pricing/" />
<link rel="alternate" hreflang="fr" href="https://example.com/fr/pricing/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/en/pricing/" />
<!-- https://example.com/de/pricing/ (German) -->
<link rel="canonical" href="https://example.com/de/pricing/" />
<link rel="alternate" hreflang="en" href="https://example.com/en/pricing/" />
<link rel="alternate" hreflang="de" href="https://example.com/de/pricing/" />
<link rel="alternate" hreflang="fr" href="https://example.com/fr/pricing/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/en/pricing/" />
<!-- https://example.com/fr/pricing/ (French): same four hreflang lines,
canonical pointing at itself -->Read it as a table of return links. English lists German and French, and German lists English and French, and French lists both. Every arrow has a matching arrow back, so Google accepts all three pairs. If you now add a Spanish page, it has to be added to the block on the English, German and French pages as well, or the Spanish pair is ignored. The x-default line points to the English page here; a language-selector page would be the other common choice.
Three ways to implement hreflang
Google says the three methods are equivalent and that using more than one brings no benefit in Search. It is also harder to manage, because two sources that disagree break pairs. Pick one.
| Method | Where it lives | Use it when | Watch out for |
|---|---|---|---|
| HTML link tags | <head> of every version | Small or medium sites, or anywhere you can edit the page template | Each new language means editing every existing version |
| XML sitemap | xhtml:link entries under each <url> | Large sites, or when templates are hard to change | The full set must be repeated under every URL; the sitemap file can only hold URLs from its own directory and below |
| HTTP Link header | Response header of the file | Files with no HTML head, such as PDFs | Hardest to inspect; needs server configuration |
HTML head, shown above, is the easiest to inspect, but adding a language means editing every existing version. XML sitemap keeps markup out of templates, which suits large sites. Declare the xhtml namespace on <urlset>, give each version its own <url>, and repeat the full set of xhtml:link children, self included, under each. The usual rules in our sitemap validator guide still apply.
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://example.com/en-us/pricing/</loc>
<xhtml:link rel="alternate" hreflang="en-us"
href="https://example.com/en-us/pricing/" />
<xhtml:link rel="alternate" hreflang="en-gb"
href="https://example.com/en-gb/pricing/" />
<xhtml:link rel="alternate" hreflang="de"
href="https://example.com/de/pricing/" />
<xhtml:link rel="alternate" hreflang="x-default"
href="https://example.com/en-us/pricing/" />
</url>
<!-- Repeat a <url> entry for /en-gb/pricing/ and /de/pricing/,
each with the same four xhtml:link lines -->
</urlset>HTTP Link header is for files without an HTML head, mainly PDFs. Each version returns the same header, including the requested file. It's wrapped here for readability.
HTTP/1.1 200 OK
Content-Type: application/pdf
Link: <https://example.com/en-us/guide.pdf>; rel="alternate"; hreflang="en-us",
<https://example.com/en-gb/guide.pdf>; rel="alternate"; hreflang="en-gb",
<https://example.com/de/guide.pdf>; rel="alternate"; hreflang="de",
<https://example.com/en-us/guide.pdf>; rel="alternate"; hreflang="x-default"Common mistakes and the symptom each one causes
Search Console no longer has a hreflang error report, so these mistakes rarely announce themselves. The symptoms below are what you typically see instead. They are patterns, not guarantees, because Google treats hreflang as a signal.
| Mistake | Symptom you will see | Fix |
|---|---|---|
| Missing return links | Google shows the wrong language or country version in results; the affected pair is ignored | List every version on every version, with identical URLs |
| Missing self-reference | The page is left out of its own cluster and the same wrong-version results appear | Add the page's own URL to its block |
Invalid codes (en-uk, es-la, region only) | That entry has no effect, so the regional version never gets picked | Use en-gb, es-mx or plain es, and a language before any region |
| Hreflang URLs that redirect, return 404 or carry noindex | Pairs are dropped, and the URL may disappear from the index | Point only at final, indexable URLs that return 200 |
| Cross-language canonical (German canonical points to English) | The Page indexing report can show "Duplicate, Google chose different canonical than user" and the German page does not appear | Give every version a self-referencing canonical |
| Relative URLs or HTTP/HTTPS and www mismatches | Return links do not match, so pairs are ignored | Use fully qualified HTTPS URLs written exactly as the canonical |
| Automatic redirect by browser language | Google and visitors only ever see one version | Google advises against these redirects; link to the other versions instead |
How to check hreflang is working
Search Console's International Targeting report used to flag hreflang errors, but Google retired it in September 2022. Checking is now on you:
Check the head of every version
Confirm the block sits inside the <head> of each version and is identical across them. An invalid element earlier in the head can close it and push the tags into the body.
Confirm every pair points both ways
Each block must list itself and every other version using exactly the same URLs. On large sites, a crawler such as Screaming Frog's SEO Spider has a Hreflang tab with filters for missing return links, non-canonical return links, missing self-references and invalid codes. It only fills in when hreflang crawling is switched on in the spider configuration.
Test each target URL
Every href should return 200 with no redirect, no noindex and a self-referencing canonical. Run doubtful ones through the Redirect Chain Checker and the Canonical URL Analyzer.
Watch which URL Google picks
URL Inspection in Search Console shows the Google-selected canonical. If a regional page reports another version as canonical, Google has folded them together.
Does Bing use hreflang?
Only weakly. In 2020 Bing's Fabrice Canel said on Twitter that hreflang is a far weaker signal than content-language at Bing, and Bing has long relied on the content-language meta tag. If Bing matters to you, add one per version: <meta http-equiv="content-language" content="en-gb">.
Check your hreflang tags
CheckSEO's Hreflang Validator fetches a live URL, lists every hreflang entry with the absolute URL it resolves to, and checks for a self-reference, duplicate codes, malformed values and a missing x-default. It checks one page at a time without following the alternates, so run each language version through it and compare the lists — a URL missing from one list is a broken return link.
Sources
- Google Search Central: Tell Google about localized versions of your page
- Google Search Central: Consolidate duplicate URLs
- Google Search Central: Managing multi-regional and multilingual sites
- Search Console Help: The International Targeting report is deprecated
- Search Engine Roundtable: Bing on hreflang (2020)
- Screaming Frog user guide: Hreflang tab
Frequently asked questions
What is hreflang used for?
Hreflang tells Google that several URLs are language or regional versions of the same page, so it can show each searcher the most appropriate one, such as the UK page in Britain and the German page to German speakers. It doesn't detect a page's language and doesn't guarantee every version gets indexed.
Do hreflang tags need return links?
Yes. If page A lists page B as an alternate but page B doesn't list page A back, Google ignores that pair. Every version should carry the same block, listing itself and every other version with identical absolute URLs. Missing return links are the most common reason hreflang silently does nothing.
What is x-default in hreflang?
x-default is a reserved hreflang value for visitors whose language settings match none of your listed versions. Google says it was designed for language-selector pages and works best with them, but it can point at any page, such as your main-market version. It is optional and needs no language code.
Is it en-uk or en-gb in hreflang?
Use en-gb. Hreflang region codes follow ISO 3166-1 alpha-2, where the United Kingdom is GB. UK is a reserved code, and Google's documentation says it ignores reserved region codes such as UK, EU and UN, so en-uk gives the page no UK targeting.
How do I check if hreflang is working?
Google retired Search Console's International Targeting report in 2022, so check manually. Confirm each version has the full block in its head, every pair links both ways, and each target URL returns 200 with no redirect, noindex or conflicting canonical. An hreflang checker or site crawler speeds this up.
Check your own site with the Hreflang Validator.
Open Hreflang ValidatorWant every check at once?
The free Full Audit runs 33 checks on any URL, most of them in seconds. Add your email afterwards and we send a detailed one-page report; the full-site report covers up to 1,000 pages.
More from the blog
Page Is Not Indexed: Every “Why Pages Aren’t Indexed” Reason in Search Console, Explained
Every "Why pages aren't indexed" reason in Google Search Console explained: what it means, whether to worry, and the fix, from 5xx errors to soft 404s.
Discovered – Currently Not Indexed: Why Google Hasn’t Crawled Your Page Yet
Discovered – currently not indexed means Google knows your URL but hasn't crawled it. When to wait, when to act, and the five fixes that move pages forward.