Ultimate Guide to Hreflang and International SEO (2026)
How hreflang actually works, why reciprocal annotations are the rule everything else hangs on, and how to test a whole hreflang set instead of guessing which country version Google will pick.
Hreflang is the annotation that tells Google which URL to serve to a searcher in France, which to a searcher in Mexico, and which to show everyone else. It does not rank your page and it does not translate your page; it swaps the right regional URL into the search result so the user lands on the version written in their language and priced in their currency. This guide covers the whole mechanism: the language and region codes, x-default, reciprocal return links, sitemap placement, and the exact errors that silently break a cluster. Every claim here is paired with Google's primary documentation or original research, and nearly every section ends with a check you can run with the tools linked inline.
What Hreflang Actually Does: Hints, Not Directives or Ranking Signals
Hreflang is an annotation, not a command. You add it to tell Google that a page exists in several languages or regional variants, and to say which URL goes with which audience. Google uses that information to decide which URL to show for a given search, but it is free to ignore your annotation and serve a different version when it thinks one is a better match. Google confirmed this in 2024, reminding site owners that hreflang tags are hints, not directives. Search Engine Journal (2024)
The same boundary applies to ranking. Hreflang is not a ranking signal. It does not push your page higher in Germany, France, or anywhere else. What it does is swap the appropriate URL into the result, so the searcher clicks a page in their language instead of a page in a language they do not read, and that targeted traffic is the real payoff. Google stated this plainly in 2019, and nothing about the mechanism has changed since. Search Engine Journal (2019)
The practical consequence is that hreflang is a correctness feature, not a growth lever. A page with broken hreflang does not lose its ranking. It loses the right audience, because German searchers land on the US English page, bounce, and buy somewhere else. That is a conversion loss you cannot see in the rankings report, which is why hreflang audits get skipped until a country's revenue dips and nobody can explain why.
What hreflang will not do
Three boundaries keep the annotation honest. Hreflang will not rank you, will not translate your content, and will not redirect a user from one URL to another. It only annotates the relationship between URLs and lets Google choose among them. If you want a user who types example.com to be bounced to example.com/de/, that is a redirect job, not an hreflang job, and the two are separated out later in this guide. If you want your French page to be found by French searchers, the translation quality is what earns that, not the tag. Google Search Central (2025)
How Google Detects Language Without Hreflang (and Why That Matters)
Here is the fact that surprises most people: Google does not use hreflang, and does not use the HTML lang attribute, to detect what language a page is written in. Its localized-versions documentation states this directly, and it is the single most misread sentence in the entire topic. Google Search Central (2025) Google runs its own language-detection algorithms over the visible text of the page, the same way it reads any other content, and those algorithms decide what language the page actually is.
Why this matters is simple. Hreflang cannot make a page count as another language. If your "French" page is really English with a few translated navigation labels, Google will detect it as English no matter which hreflang value you hang on it. The annotation is metadata about the relationship between pages; it does not change what the page says. The correct order is to translate the content first, then annotate the translated pages with hreflang so Google knows they are alternates of one another.
The two halves of the system
Think of international SEO as two independent systems that have to agree. The first is language detection, which Google does by reading your page text, and you control it by writing real translations. The second is URL serving, which hreflang controls by telling Google which URL maps to which language and region. Hreflang only touches the second system. A page can carry perfect hreflang and still be served to the wrong audience if the underlying text is not actually in the language the annotation claims.
What this means for auto-translated pages
Pages produced by raw machine translation often read as thin, duplicated, or mechanically wrong, and Google's algorithms can tell. Hreflang does not rescue them. The fix is a human review pass on the translation, because the annotation can only route a searcher to a page; it cannot make that page worth landing on. Before you annotate, confirm that the visible text of each variant genuinely matches the code you plan to give it, which is exactly the comparison a tool like the hreflang checker makes when you hand it the full cluster.
Hreflang Attribute Anatomy: ISO 639-1 Language + ISO 3166-1 Region Codes
The hreflang value is built from two standardized codes. The first is an ISO 639-1 language code, always two lowercase letters such as en for English, de for German, or es for Spanish. The second is an optional ISO 3166-1 Alpha 2 region code, always two uppercase letters such as US, GB, or MX, joined to the language with a hyphen. A language alone is valid; a language plus region is valid and more specific; a region alone is not valid. Google states this structure explicitly in its localized-versions documentation. Google Search Central (2025)
The language code must be the two-letter ISO 639-1 form, so eng is wrong and en is right, ger is wrong and de is right. The region code must be the ISO 3166-1 Alpha 2 form, and here a famous trap lives: the country code for the United Kingdom is GB, not UK. The .uk domain is an exception in the domain system, not in ISO country codes, so the correct hreflang value for a UK English page is en-gb. Getting the case right matters too, because language codes are lowercase and region codes are uppercase, and Google treats them as distinct values when they disagree.
| Code | Meaning | Valid usage |
|---|---|---|
en | English | Valid alone; covers all English speakers |
en-gb | English, Great Britain | Valid; serves UK English searchers |
en-us | English, United States | Valid; the US English variant |
de | German | Valid alone; covers all German speakers |
de-at | German, Austria | Valid; more specific than de for Austrian users |
pt | Portuguese | Valid alone; covers Portugal and Brazil together |
pt-br | Portuguese, Brazil | Valid; the Brazilian variant |
es | Spanish | Valid alone; covers all Spanish speakers |
es-mx | Spanish, Mexico | Valid; Mexican Spanish variant |
gb | Great Britain | Invalid alone; a region without a language is not a valid value |
uk | United Kingdom | Invalid as a region code; use gb |
When both a language-only value and a language-region value exist for the same language, Google treats the language-region value as more specific and prefers it for searchers it can locate in that region. A site with en, en-gb, and en-us gives Google three tiers of precision, and the searcher in London lands on the en-gb page while a searcher Google cannot locate falls back to the plain en page. That fallback chain is the reason x-default exists, covered a few sections ahead.
The Three Ways to Implement Hreflang: HTML Link, HTTP Header, XML Sitemap
Google documents three equivalent ways to publish hreflang: HTML link elements in the page head, HTTP Link headers in the response, and XML sitemaps using the xhtml:link extension. All three carry the same information, and Google treats them as interchangeable. Google Search Central (2025) The differences are about where the annotation lives and which page types each method can reach, not about which one Google trusts more.
| Method | Best for | Where it lives | Limitations |
|---|---|---|---|
HTML <link> | Most content-driven sites | In the <head> of each page | Adds bytes to every page; requires editing each template; can bloat the head on very large sites |
HTTP Link header | Non-HTML files such as PDFs, and API-served content | In the HTTP response header, not the HTML | Needs server or CDN configuration; invisible in view source, so people forget to check it |
XML sitemap xhtml:link | Large sites with thousands of variants | In the sitemap file | Requires one <url> entry per variant; errors only surface when the sitemap is read |
Which method to pick
For most sites the HTML link method is the default, because the annotation rides along with the page and is easy to see in source. The HTTP header method exists for the pages that have no head to edit, which is why it is the standard answer for PDFs. The sitemap method exists for scale, because it lets you publish every variant's annotations in one file instead of editing every template, and it keeps your HTML lean. You can use more than one method at once, but every method must agree on the same URL for the same code, because a mismatch between the HTML and the sitemap is a conflict Google has to resolve, and it may resolve it by ignoring your annotations.
They are equivalent, not additive
Because the three methods are equivalent, publishing hreflang three times does not make the signal three times stronger. It only creates three chances to introduce a typo. One clean, complete, consistent method beats a redundant pile of conflicting ones, and the rest of this guide shows how to keep whichever method you choose clean.
X-Default: When and How to Set a Locale Fallback
The x-default value points Google to the page a user should see when no other language or locale variant matches. In practice that is usually a language selector page or a homepage that lets the visitor pick a country, but it can also be your main default page when you do not want to force anyone into a specific locale. Google introduced x-default in April 2013 for international landing pages, and its current guidance still describes it as the catch-all for users whose language and region do not match any annotated variant. Google Search Central Blog (2013) Google Search Central Blog (2023)
When to set it
Set x-default whenever you have a language selector or a neutral entry page, because that is the page unmatched users should land on. Set it whenever you have no obvious single default, for example a site that serves German, French, and Italian with equal weight. If you do have one default language, you can point x-default either at that default page or at the selector, and both are defensible; the selector is the safer choice when you want visitors to choose rather than assume.
When to skip it
You can skip x-default when your site is really one language plus one regional variant and the fallback is obvious, but there is rarely a cost to adding it. A cluster with x-default is strictly more complete than one without, because it answers the question of where an unmatched searcher should go instead of leaving Google to guess. If you run a single-language site, you do not need hreflang at all, a point the FAQ section returns to.
Canonical vs Hreflang vs Redirect: A Single Decision Flow
Canonical, hreflang, and redirect answer three different questions, and most confusion comes from using one where another belongs. A canonical consolidates duplicate URLs that are the same page into one preferred URL. Hreflang points between equivalent but distinct pages that are translated or localized versions of each other. A redirect moves both the user and the crawler from one URL to another. The single question that separates them is this: are the two URLs the same page, or two different pages?
| Scenario | Canonical | Hreflang | Redirect |
|---|---|---|---|
| Two URLs are the same page in the same language (tracking params, http vs https, trailing slash) | Set canonical to the one preferred URL | Not needed; same-language duplicates are a canonical job | Optional 301 from the duplicate to the canonical, or canonical alone |
| Two URLs are translated versions of the same page | Each page canonicals to itself | Annotate each as alternate of the other, with return links | Do not redirect; a redirect would hide the localized version |
| One URL moves permanently to another (domain move, page move) | Not the primary tool | Not needed | 301 redirect the old URL to the new one |
| Same English content, region-priced with different currencies | Each page canonicals to itself | Hreflang with region codes such as en-us, en-gb, en-au | Do not redirect; let the user pick or auto-select by IP |
| A homepage that should route by language or country | Canonical to itself | x-default to the selector plus per-language alternates | Optional geo redirect, but a US-based Googlebot crawl complicates it |
The flow in three steps
First, decide whether the URLs are the same page. If yes, use canonical or a redirect, never hreflang. Second, if they are genuinely different versions, confirm each one has its own content and its own self-referencing canonical. Third, wire the hreflang annotations in both directions so every variant lists itself and every sibling. If you get the first question wrong, everything downstream is wrong, because hreflang between duplicate pages is the classic setup that generates the missing return tag errors you will meet in the audit section.
Choosing an International Site Structure: ccTLD vs Subdirectory vs Subdomain
Before you annotate anything, you have to decide where the variants live: on country-code top-level domains like example.de, in subdirectories like example.com/de/, or on subdomains like de.example.com. Google's multi-regional guidance describes the tradeoffs rather than mandating one, and the useful summary is this: a ccTLD is the clearest country signal, a subdirectory keeps all authority on one domain, and a subdomain sits in between with most of a ccTLD's complexity and none of its strongest signal. Google Search Central (2025)
| Structure | Geotargeting signal | Maintenance | Use case |
|---|---|---|---|
| ccTLD (example.de) | Strong country signal from the domain itself | Separate domains, DNS, hosting, and link profiles to manage | Established brands that want maximum local trust and a local backlink profile |
| Subdirectory (example.com/de/) | Inherits the root domain's authority; country signal via hreflang and content | One domain, one hosting bill, consolidated authority | Most sites; fastest to launch and to build authority |
| Subdomain (de.example.com) | Treated more like a separate host; weaker than a ccTLD and needs hreflang | Separate site structure under a shared root; splits analytics and authority | When a subdirectory is not possible on the platform; rarely the recommendation now |
Subdirectories are the workhorse choice because they consolidate authority and simplify maintenance, which is why most international launches start there. A ccTLD is the premium option for a country where local trust and local link equity matter enough to justify separate infrastructure, and it can still be the right call for a flagship market like Germany. The subdomain is the one to reach for only when your platform physically cannot serve a subdirectory, and even then you accept a weaker signal that hreflang has to carry on its own.
One more thing changed the calculus in 2022. Google removed the International Targeting report from Search Console, which means the old manual per-domain geotargeting that subdomains and subdirectories once leaned on is gone. Search Engine Land (2022) With manual geotargeting retired, the structure's own signal and your hreflang annotations now do more of the work, which makes the annotation quality in this guide matter more, not less. A later section covers how to validate geo-serving now that the report is gone.
Step-by-Step Hreflang Setup: URL Map, Annotations, and Return Links
Setting up hreflang is a three-step job, and skipping the first step is how most broken clusters are born. You map the URLs, you annotate every page including itself, and you make the return links exact. Here is the whole sequence.
Step 1: write the URL map
Make a plain table with one row per variant. List the language code, the region code if any, and the full URL for that version. Write the URLs as absolute addresses including the protocol, because relative URLs are invalid in hreflang and Google requires fully qualified alternates. Google Search Central (2025) For a three-language product page the map might be en at /en/product, en-gb at /en-gb/product, and de at /de/produkt. The map is your source of truth, and every later step copies from it.
Step 2: annotate every page, including itself
Each version must list itself as well as all the others. Google is explicit that every language version must be listed in the annotation set of every other version, and the self-reference is not optional. Google Search Central (2025) The complete head block for the English page looks like this:
<link rel="alternate" hreflang="en" href="https://example.com/en/product"> <link rel="alternate" hreflang="en-gb" href="https://example.com/en-gb/product"> <link rel="alternate" hreflang="de" href="https://example.com/de/produkt"> <link rel="alternate" hreflang="x-default" href="https://example.com/choose-language">
Notice the first line lists the page itself, en, and the last line lists the x-default fallback. The German page carries the same four links with its own URL in the de slot, and so on, so that every page's set is a complete roster of the cluster. That reciprocity is the entire game, and it is the next step.
Step 3: make the return links exact
A return link means that when page X lists page Y, page Y must list page X back, using the same code and the exact same URL. A missing return link, where X points to Y but Y never points back to X, can cause the whole annotation set to be ignored or misread. Google Search Central (2025) The word exact matters: a trailing slash, a http versus https difference, or a code mismatch breaks the reciprocal pair even when the pages exist. After you deploy, run each URL through the hreflang checker and confirm it reports every return link as present rather than trusting the source by eye.
Building a Sitemap With xhtml:link: Namespace and One URL Per Variant
The sitemap method moves the annotations out of the HTML and into the sitemap file, which is the cleanest option for a site with thousands of variants. It has three hard rules, all from Google's own documentation. First, the sitemap must declare the xhtml namespace with xmlns:xhtml="http://www.w3.org/1999/xhtml". Second, the sitemap needs one url element per variant, each carrying the full set of xhtml:link children. Third, those xhtml:link annotations do not count toward the sitemap's 50,000 URL limit. Google Search Central (2025)
The namespace is mandatory
Without the xmlns:xhtml declaration the parser does not recognize the xhtml:link element, and the annotations are ignored as malformed. The namespace is the single most common omission in hand-written international sitemaps, and it is invisible until something reads the file and finds nothing. Here is a minimal, correct sitemap with two of the three variants shown:
<?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/product</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/product"/>
<xhtml:link rel="alternate" hreflang="en-gb" href="https://example.com/en-gb/product"/>
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/produkt"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/choose-language"/>
</url>
<url>
<loc>https://example.com/de/produkt</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/product"/>
<xhtml:link rel="alternate" hreflang="en-gb" href="https://example.com/en-gb/product"/>
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/produkt"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/choose-language"/>
</url>
</urlset>
One url element per variant, identical children
Each variant gets its own url element, and each url element carries the identical set of xhtml:link children. If a cluster has three language versions, every one of the three url entries contains three xhtml:link children, itself plus the other two. Google Search Central (2025) The children are copies of the same roster with the loc swapped, and a single missing child in one entry breaks the reciprocal chain exactly the way a missing return tag breaks the HTML method.
Because the annotations do not count toward the 50,000 URL cap, a sitemap with 50,000 product variants and a full hreflang roster per variant stays valid, which is the main reason large sites prefer this method over bloating every page head. After you publish the file, submit it in Search Console and run it through the sitemap checker to confirm the namespace, the url structure, and the xhtml:link children all parse.
HTTP Header Hreflang for PDFs and Other Non-HTML Files
PDFs, images, and other non-HTML files have no head block to hold a link element, so the annotation has to ride in the HTTP response header instead. Google documents the HTTP Link header as the correct method for these files, and the header is the reason a translated catalog PDF can be associated with its German and French counterparts at all. Google Search Central (2025)
When the head is not available
Any file served with a content type other than text/html needs this method, and PDFs are the everyday case. You cannot edit a PDF's head because a PDF has no head; the only place to attach metadata is the response line that delivers the file. The header works for HTML pages too, but there is rarely a reason to use it there when the link element is simpler to see and edit.
The header is identical for every version
Like the HTML and sitemap methods, the HTTP header method is reciprocal, and the Link header returned for every version of a file is identical, listing the whole cluster including itself. Google Search Central (2025) For a three-language catalog the header looks like this:
HTTP/1.1 200 OK
Content-Type: application/pdf
Link: <https://example.com/en/catalog.pdf>; rel="alternate"; hreflang="en",
<https://example.com/de/katalog.pdf>; rel="alternate"; hreflang="de",
<https://example.com/fr/catalogue.pdf>; rel="alternate"; hreflang="fr",
<https://example.com/choose-language>; rel="alternate"; hreflang="x-default"
The same header is served with every one of the three PDFs, so each file is both a source and a target of the same annotation set. The practical wrinkle is that headers are configured at the server, CDN, or storage layer rather than in the file, which means the person who deploys the PDF has to remember a rule that never appears in the document itself. If your PDFs are served from a bucket or CDN, add the Link header at that layer, then confirm it with a raw header check on the URL, the kind of check the hreflang checker runs when it validates a non-HTML variant.
Copy-Paste Validators and a Fetch-Based Hreflang Tester (Runnable Tooling)
You can test hreflang without buying anything, and you should, because the errors are mechanical and a script finds them faster than an eye does. The two tools below do the two jobs that matter: one extracts the annotations from a live page, and one checks the whole cluster for self-references, absolute URLs, and return tags. Run them on your own URLs as you work through the audit sections that follow.
The quick curl check
The fastest check is a one-liner that fetches a page and prints every hreflang link in its head. It confirms the annotations exist, are absolute, and carry both a code and an href:
curl -s https://example.com/es/ | grep -oE '<link[^>]*hreflang[^>]*>'
A fetch-based tester that checks return links
The one-liner cannot see whether the other pages link back, which is the error that actually matters. The script below fetches every URL you pass it, builds a map of code to href for each, and then verifies that every href points back to the page that listed it. It is the reciprocal check from the audit checklist, automated:
import re, sys
from urllib.request import urlopen, Request
def hreflangs(url):
req = Request(url, headers={"User-Agent": "hreflang-audit/1.0"})
html = urlopen(req, timeout=15).read().decode("utf-8", "ignore")
links = re.findall(r'<link\b[^>]*>', html, re.I)
out = {}
for link in links:
code = re.search(r'hreflang="([^"]+)"', link, re.I)
href = re.search(r'href="([^"]+)"', link, re.I)
if code and href:
out[code.group(1)] = href.group(1)
return out
urls = sys.argv[1:]
cluster = {u: hreflangs(u) for u in urls}
for page, tags in cluster.items():
print(page)
for code, href in tags.items():
back = cluster.get(href, {}).get(code)
status = "return OK" if back == page else "MISSING return"
print(f" {code:10} -> {href} absolute={str(href.startswith('http')).lower()} {status}")
Run it with every variant on the command line, for example python3 hreflang_audit.py https://example.com/en/product https://example.com/en-gb/product https://example.com/de/produkt. The MISSING return line is the finding to fix first. If you want the same answer without pasting a script, the hreflang checker runs these checks in the browser for any cluster you enter, and it is the version to reach for when you are auditing a dozen URLs rather than three.
X-Default on Language-Selector Homepages: A Worked Example
Here is the setup everyone gets wrong in the abstract but right once they see it concretely. A site has a homepage at example.com that shows a language selector with no content of its own, plus three content homes at /en/, /es/, and /fr/. The selector is the page unmatched users should land on, so it becomes the x-default target, and every content page points x-default back at it.
The annotations
The English page at /en/ carries four links: itself as en, the Spanish page as es, the French page as fr, and the selector as x-default. The Spanish and French pages carry the same four with their own URL swapped into their own slot. The selector page itself lists the three content pages as alternates and points x-default at itself, closing the loop. The full set is:
<link rel="alternate" hreflang="en" href="https://example.com/en/"> <link rel="alternate" hreflang="es" href="https://example.com/es/"> <link rel="alternate" hreflang="fr" href="https://example.com/fr/"> <link rel="alternate" hreflang="x-default" href="https://example.com/">
A searcher whose language Google cannot match, or who searches from a market none of the three languages covers, is routed to the selector instead of being forced into English. That is the entire purpose of x-default, and it only works when the selector is annotated in the return direction as well. Google Search Central Blog (2023) The most common failure is treating x-default as optional decoration, annotating the three content pages, and leaving the selector out of the set, which leaves the fallback dangling and Google guessing.
Multi-Locale and Multi-Currency Pages Without Translation: A Worked Example
Not every international page is a translation. A store that ships to the US, the UK, Australia, and Canada often keeps the copy in English but changes the currency, the shipping rules, the tax handling, and the legal terms per market. Those four pages are not translations of each other, yet they are alternates, and hreflang with region codes is exactly how you keep them from cannibalizing each other.
The problem: same language, different market
Without annotation, the four near-identical English pages compete for the same English query, and Google may pick one and index the rest as duplicates. The pages are not duplicates, because the price shown in GBP on the UK page is a real, deliberate difference, but Google cannot see that intent from the words alone. Hreflang tells Google they are alternates distinguished by region, so a searcher in London is served the en-gb page and a searcher in Sydney the en-au page.
The annotations
The US page lists en-us, en-gb, en-au, and en-ca, with itself first, and every sibling returns the favor. Each page canonicals to itself, because each is the canonical version of its own market. No redirect is used, because you want all four pages indexed and served, not collapsed into one. The region code carries the entire distinction, which is the reason a language-only annotation would be wrong here: en alone cannot tell Google which market a page serves.
Why not just one page with a currency switcher
A single page with a JavaScript currency switcher cannot be served differently by market, because the URL is the same everywhere and Google indexes one version. If the price, shipping, and tax actually differ by country, they belong on separate URLs so each can rank and be served for its own market. That is the line that separates a cosmetic currency toggle from a real multi-locale setup, and it is the same line the canonical versus hreflang decision flow draws earlier in this guide.
Validating Geo-Serving After the 2022 International Targeting Report Removal
For years the International Targeting report in Search Console was where you set a country target for a domain and saw the hreflang errors Google had found. Google removed that report in 2022, retiring manual per-domain geotargeting along with it. Search Engine Land (2022) The removal did not remove hreflang itself, but it did take away the one dashboard where geo-targeting was set and verified, which means validation is now a job you assemble from other signals.
What disappeared
The report's country-targeting feature is gone, so you can no longer tell Google through Search Console that a subdirectory or subdomain should be treated as targeting a specific country. The structural signal of a ccTLD still applies, but the manual override that subdirectories and subdomains once leaned on no longer exists. What remains is hreflang, the content itself, and the structure.
What replaced it
Validate geo-serving in four ways. First, confirm the hreflang annotations are complete and reciprocal, because they now carry more of the routing weight; the hreflang checker does this in one pass. Second, watch the country filter in Search Console performance to see which URL earns impressions in which market. Third, run the pages through the on-page SEO checker to confirm each variant's title, language signals, and canonical all point at itself. Fourth, test manually from a local IP or a VPN and note which URL Google serves, because the search result is the only ground truth that matters. None of these is a drop-in replacement for the old dashboard, but together they cover the same question.
The Hreflang Audit Checklist: Self-References, Absolute URLs, Return Tags
An hreflang audit is a list of yes-or-no checks, and every no is a fix. Run the whole cluster through this checklist in order, because the checks are ordered by how much they cost when they fail. The hreflang checker automates most of these, but the list is worth knowing so you understand what each finding means.
- Every page lists itself in its own annotation set. A missing self-reference is the fastest way to get the whole cluster dropped.
- Every alternate URL is absolute and includes the protocol, http or https. Relative URLs are invalid in hreflang.
- Every annotation has a return link: page X lists page Y with a code, and page Y lists page X back with the same code and the exact same URL.
- Every code is a valid ISO 639-1 language, optionally plus an ISO 3166-1 Alpha 2 region, with the language lowercase and the region uppercase.
- No value is a region alone, and no value uses a three-letter code like eng or a wrong country code like uk for the United Kingdom.
- x-default is present when the site has a language selector or a neutral fallback, and it points somewhere real.
- Each variant's canonical points at itself, and each hreflang href points at a URL whose canonical is that same URL.
- If more than one method is used, the HTML, header, and sitemap all agree on the same URL for the same code.
The checklist reads long but each line is a second of attention, and the whole pass over a three-page cluster takes minutes. The return-link check is the one that catches the most real damage, because it is the only check that requires looking at two pages at once, which is why eyes miss it and a tool does not. For the broader page-level health around those variants, the on-page SEO checker confirms the titles, canonicals, and headings on each URL in the same sitting.
Mapping Error Strings to Fixes Across Search Console, Ahrefs, and Semrush
The same underlying mistake shows up under different names depending on which tool reports it. Knowing the mapping means you can read any of the three dashboards and reach for the same fix, because a missing return tag is a missing return tag whether Search Console calls it no return tags or Ahrefs calls it a missing return link. The table maps the strings you will actually see to the root cause and the one-line repair.
| Tool | Error message | Root cause | Fix |
|---|---|---|---|
| Search Console | No return tags | Page A links to B, but B does not link back to A | Add the reciprocal link on B pointing back to A with the same code |
| Search Console | Return tag error / conflicting return tag | The return URL or code does not match, often a trailing slash or http vs https difference | Make the href and code identical in both directions |
| Search Console | Self-referencing hreflang annotation is missing | A page lists its siblings but not itself | Add the page's own URL and code to its annotation set |
| Search Console | Unknown language code / language code is not valid | The value is not a valid ISO 639-1 language, such as eng or uk | Replace with the two-letter language code, such as en |
| Ahrefs | Hreflang annotation is missing return link | The same reciprocity problem, reported per URL | Add the reciprocal link on the target page |
| Ahrefs | Hreflang annotation points to a non-canonical URL | The href resolves to a page whose canonical is different | Point hreflang at the canonical URL and self-canonical each variant |
| Semrush | Hreflang conflict with page source code | One method disagrees with another, such as HTML versus sitemap | Make all methods list the same URL for the same code |
| Semrush | Invalid hreflang code | A malformed or unsupported language or region value | Correct to a language or language-region form in the right case |
The single most useful habit is to treat every error as a reciprocity or identity problem. Ask two questions: does the target page list me back, and is the URL I wrote the exact URL that page serves. About nine times out of ten the fix is one of those two corrections, and the rest is a code typo. After you patch, re-run the hreflang checker on the cluster and confirm the error is gone from every tool that flagged it, because the tools will re-report the same page until the return link is actually live.
The Most Common Hreflang Mistakes and Fresh Error-Prevalence Data
The most quoted statistic in hreflang writing is that 75% of multilingual websites have implementation errors, with missing return tags at the top of the list. The number is real but old: it comes from a Semrush study of roughly 100,000 domains, published in early 2016 and covering data from 2015. Search Engine Journal (2016) Guides repeat it without dating it, which leaves the impression that it is a fresh finding when it is a decade old.
The mistakes that still top the list
Missing return tags have stayed at the top of every survey of hreflang problems because they are the only error that requires two pages to cooperate. The rest of the usual suspects follow a pattern: using relative instead of absolute URLs, listing a region without a language, skipping the self-reference, pointing hreflang at a non-canonical URL, and conflicting annotations between the HTML and the sitemap. A practitioner's audit of the most common mistakes catalogs the same list, with return tags and canonical conflicts recurring first. Search Engine Journal (2025)
Why there is no fresh number
The gap in the data is itself the finding. The 2015 Semrush study is the last widely cited large-sample measurement, and since then the tool vendors have shipped better built-in validation without publishing a new prevalence figure. What that means for you is practical rather than academic: assume the return tag error is still the most likely thing wrong with your cluster, because nothing about how hreflang works has changed since the study was run. Check that one thing first, then the checklist.
Post-Deploy Verification: How to Confirm Hreflang Is Working
Deploying the tags is not the finish line; confirming they hold is. Verification has three layers, and you want all three because each catches a different failure: the source layer, the tool layer, and the search layer.
Layer 1: read the source yourself
View source on each variant and confirm the link elements are present, absolute, and identical in shape, with the self-reference in place. If you used the sitemap method, fetch the sitemap and confirm the namespace and the xhtml:link children parse. If you used the header method, run a raw header request and confirm the Link line is returned, since it will never appear in view source. The sitemap checker and the hreflang checker turn these two manual glances into a report.
Layer 2: let the tools re-crawl
Re-run the cluster through the hreflang checker and confirm zero missing return links, zero invalid codes, and zero relative URLs. Then resubmit the sitemap in Search Console and request indexing on the changed URLs so Google re-reads the annotations rather than waiting for its next crawl. The annotation only does its job after Google has seen the corrected version, and a fresh fetch is what makes that happen.
Layer 3: watch the search result
The final proof is which URL Google actually serves, and you observe that from a local IP or a VPN, not from a tool that only reads your markup. Search from a German exit node and confirm the de URL appears, then from the US and confirm the en URL does. Watch the country filter in Search Console performance over the following weeks and confirm impressions are shifting to the right variant per market. If the markup is correct but the serving is still wrong, the next suspect is the content itself, because hreflang can only route a searcher to a page Google has already decided matches the language. That is the loop back to the opening fact, and it is where this guide ends: annotate well, translate honestly, and verify in the results, not in the source. For the crawl-side fundamentals underneath all of this, the technical SEO guide covers indexing and sitemaps in depth, and the redirects and broken links guide covers the redirect half of the canonical-versus-redirect decision.
Frequently asked questions
What is hreflang and why does it matter for SEO?
Hreflang is an annotation that tells Google which URL corresponds to which language or language-and-region, so the search engine can serve the right version to the right searcher. It matters because it stops a German user from landing on your English page and bouncing, which is a conversion loss that rankings reports never show. Hreflang does not rank you, but it routes the traffic you already earn to the page that can convert it.
What is the difference between hreflang and canonical tags?
A canonical tag consolidates duplicate URLs that are the same page into one preferred URL. Hreflang points between equivalent but distinct pages that are translated or localized versions of each other. In a correct international setup each variant canonicals to itself and lists its siblings through hreflang, so the two tags answer different questions and both belong on the page.
What is x-default hreflang and when should I use it?
x-default is the hreflang value that points Google to the page a user should see when no other language or locale variant matches, typically a language selector or a neutral homepage. Use it whenever you have a selector page or no obvious single default language. It closes the fallback chain so unmatched users are routed somewhere deliberate instead of left to Google's guess.
How do I implement hreflang tags in HTML?
Add a link element to the head of each page with rel="alternate", an hreflang value such as en or en-gb, and the absolute href of that variant. Every page must list itself plus all other variants, and every listed page must link back. The head block is the default implementation for ordinary HTML pages.
How do I add hreflang to an XML sitemap?
Declare the xhtml namespace with xmlns:xhtml="http://www.w3.org/1999/xhtml" on the urlset element, then give each variant its own url element. Inside each url, add xhtml:link children for the whole cluster, with the loc swapped and the children otherwise identical. The annotations do not count toward the 50,000 URL limit.
Do hreflang URLs need to be absolute?
Yes. Alternate URLs in hreflang must be fully qualified, including the http or https protocol, and a relative URL is invalid. Use the exact absolute URL the page actually serves, including the trailing slash if it has one, because a mismatch breaks the reciprocal pair.
What happens if I use the wrong language or region code in hreflang?
Google may ignore or misread the annotation, and the tooling will flag the code as unknown or invalid. The value must be an ISO 639-1 two-letter language plus an optional ISO 3166-1 Alpha 2 region, with the language lowercase and the region uppercase, and a region alone is not valid. Correct the code and the cluster returns to working.
Why is my hreflang tag showing errors in Search Console?
The most common cause is a missing or mismatched return tag, where one page lists another but the target does not list it back with the exact same URL and code. Other causes are relative URLs, invalid codes, a missing self-reference, or a conflict between the HTML and sitemap annotations. Match the error string to the fix in the error-mapping table and re-crawl.
Does hreflang help with ranking or just with serving the right page?
Hreflang is not a ranking signal. It does not lift your position in any market. What it does is swap the right regional URL into the result, which drives targeted traffic by putting the matching page in front of the matching searcher.
How do I test whether my hreflang tags are working?
Run each URL through an hreflang checker and confirm there are no missing return links, invalid codes, or relative URLs. Then verify from a local IP or VPN which URL Google actually serves for a given country, because the search result is the ground truth. Watch the country filter in Search Console performance to confirm impressions are shifting to the right variant.
What is a missing return tag in hreflang and how do I fix it?
A missing return tag means page X lists page Y, but page Y does not list page X back with the same code and URL. It silently breaks the whole cluster because Google may ignore annotations that are not reciprocal. Fix it by adding the reciprocal link on page Y pointing back to X with the exact same code and URL.
Can I use hreflang for the same language in multiple countries?
Yes, and that is one of hreflang's most useful cases. Add region codes to the same language, such as en-us, en-gb, en-au, and en-ca, to distinguish pages that are not translated but differ by currency, shipping, or legal terms. Each page canonicals to itself, and the region code carries the distinction.
Do I need hreflang if my site is only in one language?
No. If your site serves a single language with no regional variants, there is nothing for hreflang to point between, and adding it would be noise. Hreflang earns its keep the moment you have at least two variants, whether translated or region-priced.
How does hreflang work for PDFs and other non-HTML files?
Non-HTML files have no head block, so the annotation is delivered in the HTTP Link header instead. The same Link header is returned for every version of the file, listing the whole cluster including itself. Configure it at the server, CDN, or storage layer, then confirm it with a raw header check.