How to Implement Hreflang (Step by Step)
Working code for all three hreflang methods — HTML head tags, HTTP Link headers, and XML sitemap annotations — plus the syntax rules, at-scale CMS automation, and the validation workflow to confirm it actually shipped correctly.
1 evidence signal on this page
- Related live toolreturntag - hreflang checker
There are exactly three ways to add hreflang — HTML link tags in the head, HTTP Link response headers (for non-HTML files like PDFs), or xhtml:link entries in an XML sitemap (best at scale). Pick one; Google treats all three as equivalent and there's no benefit to combining them. Every method obeys the same two non-negotiable rules: self-reference (each page lists itself) and reciprocity (if A points to B, B must point back to A, or Google ignores the pair). Codes are ISO 639-1 language plus optional ISO 3166-1 alpha-2 region; x-default is the fallback. Generate it all from a single source of truth, then validate the rendered head, not just view-source — in my study of 374,756 domains, over 67% of hreflang setups had at least one issue.
TL;DR — There are three ways to add hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others.: small
<link>tags in your page’s<head>, aLink:header your server sends, or entries in your XML sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing.. You only pick one. Whichever you pick, two rules never change: every page lists itself, and every page you link to has to link back — or Google ignores the whole set. Then you check that the tags actually show up in the page the way you meant them to.
Start here: you’ve already decided you need hreflang
This is the how-to. If you’re still not sure whether you need hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. or what it does, read the hreflang overview first — this page assumes you know you have multiple language or country versions of a page and you just want to build the thing correctly.
The three ways to add it (pick one)
- HTML
<link>tags in the<head>. You add a few lines to the top of each page’s HTML. Easiest to understand, easiest to see, good for smaller sites. - HTTP
Link:headers. The same information, sent by your server in the response instead of in the HTML. This is the only option for files that aren’t HTML — like a PDF, which has no<head>to put tags in. - XML sitemapAn XML sitemap is a UTF-8 file listing the canonical URLs on your site (with optional lastmod) so search engines can discover and prioritize them. It's a discovery and diagnostic aid, not a guarantee of indexing — and Google ignores its priority and changefreq tags.. You list all the language versions inside your sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. file instead of on each page. Best for big sites, because you don’t have to touch every page — the whole map lives in one place.
Google treats all three the same. There’s no “faster” or “stronger” one, and there is no benefit to using more than one at a time — that just gives you more places for things to fall out of sync.
Evidence for this claim Google supports equivalent HTML, HTTP-header, and sitemap methods for declaring localized versions; HTTP headers can be used for non-HTML files such as PDFs. Scope: Google Search hreflang implementation methods. Confidence: high · Verified: Google: Localized versionsWhat the HTML version looks like
Say you have a US English page, a UK English page, a German page, and a global homepage that lets people choose. On the US English page you’d put:
<link rel="alternate" hreflang="en-us" href="https://example.com/us/" />
<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="x-default" href="https://example.com/" />Read each line as: “there’s an alternate version of this page, it’s for this
language/region, and it lives at this address.” The x-default line is your
fallback for anyone whose language doesn’t match the others.
Two things to notice, because they’re the two rules that make hreflang work:
- The US page lists itself (that first
en-usline points at the US page you’re already on). - Every other page in the set has to carry the same block pointing back. The UK page, the German page, and the homepage all need their own version of these four lines.
Make a two-page hreflang cluster reciprocal
htmlBefore
removed
<!-- /en-us/shoes/ -->
<link rel="alternate" hreflang="de" href="https://example.com/de/schuhe/">
<!-- /de/schuhe/ -->
<link rel="alternate" hreflang="de" href="https://example.com/de/schuhe/">
Fixed
added
<!-- /en-us/shoes/ -->
Added line.
<link rel="alternate" hreflang="en-us" href="https://example.com/en-us/shoes/">
<link rel="alternate" hreflang="de" href="https://example.com/de/schuhe/">
<!-- /de/schuhe/ -->
Added line.
<link rel="alternate" hreflang="en-us" href="https://example.com/en-us/shoes/">
<link rel="alternate" hreflang="de" href="https://example.com/de/schuhe/">
- The English page now lists itself.
- The German page now links back to the English page.
- Both documents expose the same complete set of alternates.
The two rules, in plain terms
- Every page points back. If your US page links to your German page, the German page has to link to the US page. Miss that return link and Google throws the pair out. This is the rule people break most.
- Every page points to itself. Each version lists its own URL in the set. Google calls this optional but good practice — do it anyway, it keeps everything consistent.
Use real, complete web addresses
Always use the full address, starting with https://. Not /us/, not
//example.com/us/ — the whole thing, https://example.com/us/. And it has to
match the exact address Google actually indexes: same protocol, same www (or
not), same trailing slashA trailing slash is the forward slash (/) at the end of a URL — example.com/page/ versus example.com/page. Except at the bare root domain, the two versions are different URLs to search engines, so you pick one format and enforce it., same capitalization.
Get the codes right
The code is a two-letter language, optionally followed by a dash and a two-letter
country: en, en-us, de, es-mx. The classic mistakes are en-uk (it’s
en-gb — uk actually means Ukrainian) and jp for Japanese (it’s ja).
Then check that it worked
The most important thing beginners miss: after you ship, actually look at the
rendered page to confirm the tags are there and in the <head>. If your tags are
added by JavaScript, they might not show up when you “View Page Source” but will
show up in the live page. Google Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results.’s URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. can show you what
Google actually rendered.
Want full code for the header and sitemap methods, how to automate this across a whole CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms., the exact validation steps, and the mistakes that quietly break clusters? Switch to the Advanced tab.
TL;DR — Three methods, pick one: HTML
<link>tags in the<head>, HTTPLink:headers (the only option for non-HTML files like PDFs), or<xhtml:link>entries in an XML sitemapAn XML sitemap is a UTF-8 file listing the canonical URLs on your site (with optional lastmod) so search engines can discover and prioritize them. It's a discovery and diagnostic aid, not a guarantee of indexing — and Google ignores its priority and changefreq tags. (best at scale — one machine-generated file, easiest to QA). Google says the three are equivalent and there’s no benefit to combining them. Every method obeys self-reference + reciprocity, uses absolute URLs, and uses ISO 639-1Two-letter language codes used in hreflang (en, es, de). language + optional ISO 3166-1 alpha-2Two-letter country codes used in hreflang region targeting (us, gb, au). region codes. Generate the whole thing from one source of truth — hand-maintained hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. rots. Then validate the rendered head, crawl the whole cluster for reciprocity, and keep re-checking after every URL change. Do not auto-redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. by geoGenerative Engine Optimization (GEO) is the practice of optimizing content and brand presence so AI-powered search engines and assistants — Google AI Overviews, ChatGPT, Perplexity — cite, recommend, or mention you when generating answers. Google's position is that it's still SEO..
Before you write a line of code: three decisions
1. Which method. Google is explicit that the choice is about convenience, not performance — “The three methods are equivalent from Google’s perspective and you can choose the method that’s the most convenient for your site.” My rough rule:
Evidence for this claim Google supports equivalent HTML, HTTP-header, and sitemap methods for declaring localized versions; HTTP headers can be used for non-HTML files such as PDFs. Scope: Google Search hreflang implementation methods. Confidence: high · Verified: Google: Localized versions- A handful of URLs, a static or simple site, few locales → HTML
<link>tags. - Non-HTML assets (PDFs, docs) → HTTP
Link:headers (you have no other option — there’s no<head>in a PDF). - Many locales, an existing sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. pipeline, or a headless/JAMstack setup → XML sitemapAn XML sitemap is a UTF-8 file listing the canonical URLs on your site (with optional lastmod) so search engines can discover and prioritize them. It's a discovery and diagnostic aid, not a guarantee of indexing — and Google ignores its priority and changefreq tags., generated programmatically.
The Decision Trees lens walks this as an actual flowchart.
2. One source of truth. Whatever method you pick, the annotations should be generated from one place — a locale/translation table in your database, a CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. relationship field, or (for small sites) a single spreadsheet. The single worst hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. anti-pattern is hand-maintaining tags per page. The moment one locale’s template drifts, return links go missing and pairs get dropped.
3. Do not combine methods. You can run all three; Google says there’s no benefit, and every extra method is another surface for the three copies to disagree with each other.
Evidence for this claim Google requires fully qualified alternate URLs and reciprocal links, and recommends including each page itself in its alternate set. Scope: Google Search hreflang rules shared by all delivery methods. Confidence: high · Verified: Google: Hreflang guidelinesMethod 1 — HTML <link> tags in the <head>
The syntax, verbatim from Google, is:
<link rel="alternate" hreflang="lang_code" href="url_of_page" />A full working set for a multi-language, multi-region cluster with a fallback:
<link rel="alternate" hreflang="en-us" href="https://example.com/us/" />
<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="x-default" href="https://example.com/" />That exact block goes on every page in the cluster (the US page, the UK page, the German page, and the homepage) — each one includes its own self-referencing line. That’s what satisfies reciprocity.
Placement is a hard rule. Google: “The <link> tags must be inside a
well-formed <head> section of the HTML.” And their own troubleshooting advice:
“If in doubt, paste code from your rendered page into an HTML validator to ensure
that the links are inside the <head> element.”
This matters more than it sounds, because of a failure mode most written guides
skip: hreflang tags can be forced out of the <head> and into the <body>,
where they’re invalid. In my Pubcon Vegas 2019 deck
I flagged this directly — tags can’t legitimately live in the body (that would let
one site hijack another’s alternates), but a malformed or injected <p> tag, or an
iframe, can prematurely close the <head> so that everything after it — including
your hreflang — renders inside the <body>. The tag is technically present in
source but silently invalid. The fastest way to debug it is browser DOM
breakpoints: watch where the tags actually land in the rendered DOM, then walk
back to the markup that broke the <head>.
When HTML tags make sense: small-to-medium sites with a manageable number of
locales, where the per-page <link> block doesn’t balloon. On a site with dozens
of locales, every page carries a large block of markup — which is one reason big
sites lean on the sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. method.
Don’t mix hreflang with other alternate attributes on the same
<link> element. Google’s guidance is explicit that a <link rel="alternate">
carrying hreflang shouldn’t also carry an unrelated alternate attribute like
media in the same tag — if you need both a language/region alternate and a
media-query alternate for the same URL, that’s two separate <link> elements,
not one combined one. Mixing them is an easy way to end up with a tag Google
can’t parse as either.
Method 2 — HTTP Link: headers
Same information, sent in the HTTP response instead of the HTML. The syntax:
Link: <https://example.com/file.pdf>; rel="alternate"; hreflang="en",
<https://de-ch.example.com/file.pdf>; rel="alternate"; hreflang="de-ch"Note the angle brackets around each URL, the semicolon-separated attributes, and the comma separating each alternate. Every URL in the header is comma-appended.
When you need this: non-HTML resources. A PDF, a .doc, an image served
directly — none of them have a <head> to hold <link> tags, so the header is
your only way to attach hreflang to them.
Configuration considerations: you set these headers at the server or CDN layer
(an Apache Header directive, an Nginx add_header, a Cloudflare/Fastly/CloudFront
response-header rule, or your application’s response). Because the header is set by
infrastructure rather than per-document markup, the reciprocity rule is easy to
break here — the English PDF’s header and the German PDF’s header are usually
configured separately, so it’s on you to make sure each one lists the whole set,
itself included. Keep the header generation driven by the same locale table as your
HTML/sitemap approach.
The invariant to hold onto: every alternate response carries the identical complete set, every time. It’s not enough for the English PDF’s header to list the German alternate — the German PDF’s response has to carry the exact same set back (itself plus every other alternate), on every single response, not just the first one a crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. happens to hit. Treat the header as generated output, not a one-off you set and forget.
Method 3 — XML sitemap <xhtml:link> annotations
At scale, this is usually the right call: the whole cluster lives in one (or a few)
machine-generated files, nothing bloats each page’s <head>, and — because the
entire relationship graph is in one place — it’s by far the easiest method to QA.
The syntax:
<?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://www.example.com/english/page.html</loc>
<xhtml:link rel="alternate" hreflang="de"
href="https://www.example.de/deutsch/page.html"/>
<xhtml:link rel="alternate" hreflang="en"
href="https://www.example.com/english/page.html"/>
</url>
<url>
<loc>https://www.example.de/deutsch/page.html</loc>
<xhtml:link rel="alternate" hreflang="de"
href="https://www.example.de/deutsch/page.html"/>
<xhtml:link rel="alternate" hreflang="en"
href="https://www.example.com/english/page.html"/>
</url>
</urlset>Two things that trip people up in the sitemap method:
- The namespace declaration is mandatory. That
xmlns:xhtml="http://www.w3.org/1999/xhtml"on the<urlset>element is not optional decoration — omit it and every<xhtml:link>in the file is invalid. - Every
<url>block must be self-complete. Notice that both<url>blocks above list both alternates, including their own<loc>. Each<url>entry carries the full set (self-reference + all alternates). Reciprocity in a sitemap is just “every URL’s block lists every URL in the cluster, itself included.”
Two behaviors worth knowing so you don’t over-engineer the generator: the order
of the <xhtml:link> children inside a <url> block doesn’t matter to Google —
don’t waste time sorting them — and those <xhtml:link> annotations don’t count
against your sitemap’s 50,000-URL-per-file limit, since they’re children of a
<url> entry, not separate <url> entries themselves.
Generating it programmatically. The whole point of the sitemap method is that
it’s a byproduct of your CMS’s own translation data. If your CMS already knows
that /english/page.html and /deutsch/page.html are translations of each other,
your sitemap generator should walk that relationship table and emit the
<xhtml:link> blocks at build time (or at sitemap-request time). Do that and
hreflang can’t drift out of sync with reality — it’s regenerated from the source of
truth every time, and adding a locale is a data change, not a hand-edit across
hundreds of pages.
For teams without dev resources, I built a lightweight Google Sheets template in my Ahrefs hreflang guide: a Setup tab (pick a default language plus up to four variants), a URLs tab (paste each language’s URLs into columns), and a Results tab that auto-generates the sitemap XML block for you. It’s the “single source of truth” idea made concrete for sites too small to justify a real CMS integration.
The rules that apply no matter which method you pick
These are method-agnostic and non-negotiable.
- Self-reference. Every page (or every
<url>block, or every header) lists itself. Mueller frames this as optional-but-good-practice, but skipping it was present in 18.0% of the domains in my study — automate it and it costs nothing. - Reciprocity. “Each language version must list itself as well as all other language versions.” And the enforcement: “If two pages don’t both point to each other, the tags will be ignored. This is so that someone on another site can’t arbitrarily create a tag naming itself as an alternative version of one of your pages.” One missing return link drops the pair.
- Absolute, fully-qualified URLs. “Alternate URLs must be fully-qualified,
including the transport method (http/httpsHTTPS is the encrypted version of HTTP — it uses TLS to authenticate the server and protect data in transit between a browser and a website. Google announced it as a lightweight ranking signal in 2014 and today conditionally prefers HTTPS pages as canonical; Chrome marks plain HTTP pages 'Not Secure.')” — so
https://example.com/foo, never//example.com/fooor/foo. And the URL must match the exact form Google indexes: protocol,www, trailing slashA trailing slash is the forward slash (/) at the end of a URL — example.com/page/ versus example.com/page. Except at the bare root domain, the two versions are different URLs to search engines, so you pick one format and enforce it., and case all have to line up, or the return-link match fails.
Getting the codes right
“The first code of the hreflang attribute is the language code (in ISO 639-1
format) followed by an optional second code that represents the region code (in ISO
3166-1 Alpha 2 format).” Combine them with a dash: en-US. You can target a
language on its own (es = Spanish everywhere), but you cannot target a region
on its own — there’s always a language first.
The mistakes I see most often (and saw across the study dataset):
en-UKinstead ofen-GB—ukis Ukrainian, the UK’s region code isgb.jpinstead ofjafor Japanese,cninstead ofzhfor Chinese.- Three-letter codes (
ger,eng) where two-letter ISO 639-1 is required. - Using
EU,UN, orUKas region codes — none are valid ISO 3166-1 alpha-2 targets.
Lint locale codes and generate a consistent cluster from one URL matrix with the Hreflang Generator + Linter Free
- Enter each language or language-region code with its absolute locale URL.
- Fix invalid codes, separators, duplicates, and URL-format errors before exporting tags.
- Deploy from the same source of truth, then crawl the live cluster separately to confirm self-reference and reciprocity.
A focused Hreflang Generator error says en_US uses an underscore, explains that hreflang subtags are hyphen-separated, and recommends en-US.
x-default is the reserved value for the fallback — a language selector or an
auto-redirecting home page that serves users who match none of your explicit
locales:
<link rel="alternate" href="https://example.com/" hreflang="x-default" />It’s not mandatory. It was the single most-missing element in my study (56.3% of
domains omitted it), but a missing x-default doesn’t break the cluster the way a
missing reciprocal tag does — Google just falls back to its own language/region
detection for unmatched users. Add it anyway; it’s a checklist item, not a
cluster-breaker. (There’s a dedicated x-defaultx-default is the reserved hreflang value that points to a fallback URL — the page Google shows when a user's locale doesn't match any of your other hreflang tags. It is optional and does not mean \"English.\" subtopic in this cluster.)
Implementing at scale — CMS and platform approaches
WordPress. Yoast SEO does not generate hreflang on its own. To actually
output tags you need a multilingual plugin — WPML or Polylang. WPML
auto-generates hreflang for every page that has translations, adds an x-default
pointing at your default-language version, and by default injects the annotations
into the XML sitemap; there’s a setting under WPML → Languages → SEO Options
(“Display alternative languages in the HEAD section”) if you want head-tag output
instead of, or in addition to, the sitemap. (See WPML’s docs on using it with
Yoast.)
Shopify. Shopify Markets automatically generates mutually-linked hreflang
tags once you’ve configured markets/languages and the content is published and
linked in navigation — which removes the most common failure mode (missing
reciprocal links) by design. The catch: Markets’ automatic tags are often
language-only (fr, de) rather than language-region (fr-FR, fr-CA), which
under-serves brands that need regional specificity — French for France vs. Canada
vs. Belgium. For that you drop to manual <link> tags in theme.liquid (Shopify’s
own theme hreflang docs
show the pattern) or an app — and be careful, because mixing automatic Markets
tags with manual/app tags is a documented source of conflicts. Pick one.
Custom / headless / enterprise. Generate the annotations from your translation-relationship table at build or serve time, as described in the sitemap section above. This is the same “single source of truth” principle — hreflang becomes a computed output of data your CMS already holds, not a hand-maintained artifact that can rot.
Implementation mistakes that break the cluster
Auto-redirecting by geoGenerative Engine Optimization — visibility inside AI answer engines./IP. This is a separate failure from syntax errors and it’s worse. If you redirect visitors — and especially crawlers — to a version based on perceived location, you can de-index entire regional clusters, because GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. mostly crawls from the US. As I put it in that Pubcon deck: a geo-redirectA geo-redirect automatically sends a visitor to a location- or language-specific URL based on IP or browser signals — a UX/serving mechanism that's separate from, and can actively undermine, hreflang. “would redirect search engines to where they crawl from. Google for instance mostly crawls from the US so we would effectively de-index all geo pages.” There’s a regulatory angle too — potential exposure under EU anti-geoblocking rules. The right pattern is redirect users, never crawlers: detect and (optionally) redirect human visitors, but always let bots reach every URL variant directly, with hreflang doing the actual routing signal. Google’s own multi-regional guidance recommends a non-intrusive suggestion banner over automatic redirection for exactly this reason.
Pointing hreflang at non-canonical, redirected, or noindexed URLs. If a locale’s
URL changes and the redirect goes in but the hreflang still points at the old URL,
your cluster now references a 301 or a 404 (16.9% of domains in my study
referenced broken/redirected pages). Similarly, each variant should canonicalize to
itself; pointing hreflang at a URL that’s canonicalized away, or at a noindexed
page, breaks the return link (8.0% pointed at non-canonical URLs).
Inconsistent URL formats. The hreflang URL and the indexed URL have to be
byte-identical in form — trailing slashA trailing slash is the forward slash (/) at the end of a URL — example.com/page/ versus example.com/page. Except at the bare root domain, the two versions are different URLs to search engines, so you pick one format and enforce it., www, protocol, and case all included. A
mismatch here is a silent reciprocity failure.
Validating your implementation after launch
View rendered source, not just raw source. If your hreflang is injected by
client-side JavaScript, curl or Ctrl+U (“View Page Source”) will show nothing —
but the tags exist in the rendered DOM. Confirm with GSC URL Inspection → “Test Live
URL” → “View Tested Page,” or a renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM.-capable crawler. This is the single most
common reason someone says “my tags are missing” when they’re actually fine (or the
reverse — present in source but broken because they render in the <body>).
Crawl the whole cluster, don’t spot-check one URL. Reciprocity is a relationship between pages, so checking one page tells you almost nothing. Run a crawler across the whole cluster — Screaming Frog’s hreflang audit or Ahrefs Site Audit — to catch missing return tags, non-canonical targets, and broken references at scale. Ahrefs Site Audit’s Hreflangs tab draws the cluster as a graph with broken links in red, which is far easier to reason about than a CSV.
Verify real SERPs with &hl= and &gl=. Append the host-language (&hl=) and
geolocation (&gl=) parameters to a Google search URL to preview what a given
locale’s results actually look like, rather than guessing from your own location.
Validation is not a one-time step. New locales, URL/redirect changes, and dev/staging config bleeding into production are the recurring causes of post-launch breakage. Build hreflang checks into regression tests and recurring crawls, not just a launch-day QA pass. My framing from the talks: “any number of things can break from masking to things carrying over from dev/test/staging environments.”
Myths worth retiring
- “Sitemaps process faster than HTML tags.” False. Both are resolved at crawl time — I’ve debunked this directly. The sitemap’s advantage is maintainability and QA, not speed.
- “Yandex doesn’t support hreflang in sitemaps.” False — Yandex’s own documentation confirms sitemap hreflang support.
- “Use all three methods for extra signal.” No benefit per Google, and it just multiplies inconsistency risk.
- “A missing
x-defaultbreaks the cluster.” False — it’s optional; Google falls back to its own detection. - “Wrong hreflang gets you penalized.” False — it’s a hint, not a directive. Broken hreflang is ignored, not penalized.
Where to go next
This article is the how-to depth under the hreflang hub — the hub covers what hreflang is, why reciprocity matters, and what Bing does instead. The x-defaultx-default is the reserved hreflang value that points to a fallback URL — the page Google shows when a user's locale doesn't match any of your other hreflang tags. It is optional and does not mean \"English.\" subtopic goes deep on the fallback value. For the strategy this implements, see the International SEOInternational SEO is the practice of optimizing a site so search engines understand which countries and/or languages it targets, and serve the right version to each user. It spans URL structure, hreflang, and on-page localization. pillar — hreflang is the technical layer, not a substitute for genuine localizationLocalization is adapting content for a specific target market — not just translating the words, but adjusting currency, formats, idioms, cultural references, local search terms, and trust signals so the experience feels native..
AI summary
A condensed take on the Advanced version:
- Three methods, pick exactly one (Google treats them as equivalent; no benefit
to combining):
- HTML
<link>tags in the<head>— small/medium sites; must be in a well-formed<head>, never the<body>; don’t mixhreflangwith another alternate attribute likemediaon the same<link>element. - HTTP
Link:headers — the only option for non-HTML files (PDFs); set at server/CDN; every alternate response must carry the identical complete set, every time. - XML sitemapAn XML sitemap is a UTF-8 file listing the canonical URLs on your site (with optional lastmod) so search engines can discover and prioritize them. It's a discovery and diagnostic aid, not a guarantee of indexing — and Google ignores its priority and changefreq tags.
<xhtml:link>— best at scale; needs thexmlns:xhtml="http://www.w3.org/1999/xhtml"namespace on<urlset>; easiest to QA because the whole graph is in one file; child order doesn’t matter and these children don’t count toward the 50,000-URL sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. limit.
- HTML
- Two universal rules: self-reference (each page lists itself) and reciprocity (A→B requires B→A, or the pair is ignored). Use absolute, fully-qualified URLs that match the exact indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. form.
- Codes: ISO 639-1Two-letter language codes used in hreflang (en, es, de). language + optional ISO 3166-1 alpha-2Two-letter country codes used in hreflang region targeting (us, gb, au). region (
en-GB, noten-UK;ja, notjp).x-defaultis the reserved fallback — optional but the most-missed element (56.3% in my study). - Automate from one source of truth. WordPress needs WPML/Polylang (Yoast alone does nothing); Shopify Markets auto-generates reciprocal tags but often language-only; custom/headless should emit hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. from the translation table.
- Don’t auto-redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. by geoGenerative Engine Optimization (GEO) is the practice of optimizing content and brand presence so AI-powered search engines and assistants — Google AI Overviews, ChatGPT, Perplexity — cite, recommend, or mention you when generating answers. Google's position is that it's still SEO. — GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. crawls mostly from the US, so it can de-index regional clusters; redirect users, never bots.
- Validate the rendered head, not just view-source (JS-injected tags won’t show
in source); crawl the whole cluster for reciprocity; check locales with
&hl=/&gl=; re-check after every URL change.
Official documentation
Primary-source documentation for implementing hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others..
- Localized versions of your pages — the primary implementation doc: all three methods with exact syntax, the reciprocity requirement, valid codes, the absolute-URL rule, and
x-default. - Managing multi-regional and multilingual sites — URL-structure options and the auto-redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. / cloaking warning (why you must not geoGenerative Engine Optimization (GEO) is the practice of optimizing content and brand presence so AI-powered search engines and assistants — Google AI Overviews, ChatGPT, Perplexity — cite, recommend, or mention you when generating answers. Google's position is that it's still SEO.-redirect crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index.).
- Tell Google about localized versions (x-default blog, 2013) — the original introduction of
x-default. - International Targeting report deprecation (Sept 2022) — the old report is gone; hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. tags still work.
Bing / Microsoft
- Bing Webmaster Guidelines — Bing’s guidance; note Bing leans on
content-languageand<html lang>over hreflang. - Bingbot Series: Maximizing Crawl Efficiency — context on how Bing handles international/multilingual sites.
CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. / platform
- WPML — Using WordPress SEO (Yoast) with WPML — how WPML outputs hreflang (head vs. sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. setting).
- Shopify — Add hreflang tags in your theme — the manual
theme.liquid<link>pattern.
Quotes from the source
On-the-record statements relevant to implementation. Each Google-docs link is a deep link that jumps to the quoted passage on the live page.
Google — the three methods
- “The three methods are equivalent from Google’s perspective and you can choose the method that’s the most convenient for your site.” — Google Search Central docs. Jump to quote
Google — placement
- “The
<link>tags must be inside a well-formed<head>section of the HTML.” — Google Search Central docs. Jump to quote
Google — the two rules
- “Each language version must list itself as well as all other language versions.” — Google Search Central docs. Jump to quote
- “If two pages don’t both point to each other, the tags will be ignored.” — Google Search Central docs. Jump to quote
- “Alternate URLs must be fully-qualified, including the transport method (http/httpsHTTPS is the encrypted version of HTTP — it uses TLS to authenticate the server and protect data in transit between a browser and a website. Google announced it as a lightweight ranking signal in 2014 and today conditionally prefers HTTPS pages as canonical; Chrome marks plain HTTP pages 'Not Secure.').” — Google Search Central docs. Jump to quote
Google — codes
- “The first code of the hreflang attributeHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. is the language code (in ISO 639-1Two-letter language codes used in hreflang (en, es, de). format) followed by an optional second code that represents the region code (in ISO 3166-1 Alpha 2 format).” — Google Search Central docs. Jump to quote
John Mueller, Google — it’s a hint, not a directive
- On self-referential tags: hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. self-references are reported as optional but good practice. — John Mueller, Google, relayed via my Ahrefs hreflang guide.
- On correctness not guaranteeing outcome (May 2025, Bluesky): Mueller noted that hreflang doesn’t guarantee indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed., so a variant may simply not be indexed, and that same-language variants (like
fr-frandfr-be) are commonly consolidated. — relayed via Search Engine Journal coverage.
Which implementation method should I use?
Work top to bottom and stop at the first match.
1. Are the pages non-HTML files (PDFs, docs, images served directly)?
→ Yes → HTTP Link: headers. They have no <head>, so this is your only
option. Set the header at the server/CDN, listing the whole set on each file.
→ No → continue.
2. Do you have more than a handful of locales, an existing sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. pipeline, or a
headless/JAMstack build?
→ Yes → XML sitemapAn XML sitemap is a UTF-8 file listing the canonical URLs on your site (with optional lastmod) so search engines can discover and prioritize them. It's a discovery and diagnostic aid, not a guarantee of indexing — and Google ignores its priority and changefreq tags. <xhtml:link>. Generate it programmatically from your
translation table. One machine-generated file, no per-page markup, easiest to QA.
→ No → continue.
3. Small/simple site, few locales, and you’d rather keep everything visible on the
page?
→ HTML <link> tags in the <head>. Just make sure the block is generated from
one source of truth and lands inside a well-formed <head>.
Whatever you pick: use it alone. Google says there’s no benefit to combining methods, and every extra copy is a place for the three to disagree.
Do I need x-default?
Do you have a page that serves users who match none of your explicit locales — a
country/language selector, or a global homepage?
→ Yes → add x-default pointing at that fallback page.
→ No → you can skip it. It’s optional; Google falls back to its own detection. It
won’t break the cluster (unlike a missing reciprocal tag). Adding it is still good
practice — it was the single most-missed element in my study (56.3%).
Should I auto-redirect users by location?
Are you thinking about redirecting based on IP/geoGenerative Engine Optimization (GEO) is the practice of optimizing content and brand presence so AI-powered search engines and assistants — Google AI Overviews, ChatGPT, Perplexity — cite, recommend, or mention you when generating answers. Google's position is that it's still SEO.? → RedirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. human visitors only, and prefer a non-intrusive banner over a hard redirect. → Never redirect crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. by geoGenerative Engine Optimization — visibility inside AI answer engines.. GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. mostly crawls from the US, so a crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. geo-redirectA geo-redirect automatically sends a visitor to a location- or language-specific URL based on IP or browser signals — a UX/serving mechanism that's separate from, and can actively undermine, hreflang. can de-indexStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. your other regional versions — and it risks cloaking classification and EU anti-geoblocking exposure. Let bots reach every URL variant directly; hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. does the routing signal.
Which CMS path applies to me?
- WordPress? → Yoast alone does nothing. Install WPML or Polylang; they emit hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. (choose head vs. sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. output in WPML’s SEO settings).
- Shopify? → Markets auto-generates reciprocal tags — but often language-only.
Need
fr-FRvsfr-CA? Add manualtheme.liquidtags or an app, and don’t mix the two (conflict risk). - Custom / headless? → Emit
<xhtml:link>(or head tagsMeta tags are HTML elements in a page's head that pass metadata about the page to search engines and browsers. For SEO only a few matter — the title element, the meta description, and the robots meta tag — while meta keywords and most others are ignored.) from your translation-relationship table at build/serve time.
SOP: Ship a hreflang cluster from scratch
A repeatable procedure for adding a new hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. cluster (or a new locale to an existing one). Run it top to bottom.
1. Build the locale matrix (single source of truth).
List every URL and its language-region code in one place — a database table, a CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms.
translation field, or a spreadsheet. Confirm every URL is the canonical, indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed.
form (right protocol, www, trailing slashA trailing slash is the forward slash (/) at the end of a URL — example.com/page/ versus example.com/page. Except at the bare root domain, the two versions are different URLs to search engines, so you pick one format and enforce it., case). This table is the input to
everything below; nothing gets hand-typed downstream.
2. Pick one method using the Decision Trees lens. Do not combine methods.
3. Generate the annotations from the matrix.
- HTML: emit the
<link>block into each page’s<head>from the matrix. - SitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing.: emit each
<url>block with thexmlns:xhtmlnamespace on<urlset>. - Headers: emit the
Link:header from the matrix at the server/CDN.
4. Verify the two rules programmatically before publishing. Every entry must (a) include a self-reference and (b) list every other entry in the cluster. Confirm reciprocity: for each A→B, there’s a matching B→A.
5. Add x-default if you have a selector or global fallback page.
6. Publish, then validate the rendered output (see the Playbooks lens for the
detailed validation runbook): rendered head (not view-source), a full-cluster crawl
for reciprocity, and a &hl=/&gl= SERP spot-check.
7. Wire it into ongoing checks. Add a recurring crawl / regression test so a future URL change or new locale can’t silently rot a return tag. Validation is not a one-time task.
When adding a locale later: you only edit the matrix (step 1) and re-run steps 3–6. If you’re hand-editing individual pages to add a locale, your source of truth is wrong — fix that first.
Playbook: “My hreflang isn’t working” — validation runbook
Run these in order. Each step either finds the break or clears a suspect.
Step 1 — Confirm the tags actually render. Open the page and view the rendered DOM (GSCA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. → Test Live URL → View Tested Page, or a renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index.). Do not rely on Ctrl+U “View Page Source” — if hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. is JS-injected it won’t appear there even though it’s live.
- Tags present in rendered head → go to Step 3.
- Tags missing from rendered head → Step 2.
Step 2 — Are the tags in the <head> or the <body>?
If the tags exist in source but sit inside <body>, they’re invalid. A malformed or
injected <p> tag or an iframe likely closed the <head> early. Use browser DOM
breakpoints to find where the <head> breaks, fix that markup, re-check.
Step 3 — Check the URLs are absolute and canonical.
Every href must be fully-qualified (https://…) and byte-identical to the indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed.
form (protocol, www, trailing slashA trailing slash is the forward slash (/) at the end of a URL — example.com/page/ versus example.com/page. Except at the bare root domain, the two versions are different URLs to search engines, so you pick one format and enforce it., case). Confirm none point at a 301, 404,
noindexed, or canonicalized-away URL.
Step 4 — Check reciprocity across the whole cluster. Crawl the entire cluster (Screaming Frog / Ahrefs Site Audit). For every A→B, verify a matching B→A exists, and that each page self-references. This is where most breaks live — a single missing return tag drops the pair.
Step 5 — Validate the codes.
Confirm ISO 639-1Two-letter language codes used in hreflang (en, es, de). language + ISO 3166-1 alpha-2Two-letter country codes used in hreflang region targeting (us, gb, au). region. Look specifically for
en-UK (→ en-GB), jp (→ ja), three-letter codes, and region-only codes.
Step 6 — Rule out geo-redirectsA geo-redirect automatically sends a visitor to a location- or language-specific URL based on IP or browser signals — a UX/serving mechanism that's separate from, and can actively undermine, hreflang.. Confirm crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. aren’t being geoGenerative Engine Optimization — visibility inside AI answer engines.-redirected. If GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. (crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor. from the US) gets bounced to your US version, your other regional URLs may never be reached.
Step 7 — Reset expectations if the cluster is technically correct.
If everything above checks out and same-language variants (e.g. fr-fr / fr-be)
are still consolidated in reporting, that’s expected — Google can consolidate
near-identical same-language variants regardless of implementation. It’s a hint, not
a directive; wrong or ignored hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. is not a penalty. Stop chasing it as a bug.
Implementation anti-patterns
Concrete mistakes, why they’re wrong, and what to do instead.
1. Hand-maintaining hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. per page. Why it’s wrong: the moment one template or locale drifts, return tags go missing and pairs get dropped — reciprocity rot at scale. Do instead: generate every annotation from one source of truth (translation table, CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. field, or the Sheets template for small sites), so the whole cluster is regenerated, not edited.
2. Using all three methods for “extra signal.” Why it’s wrong: Google says there’s no benefit, and three copies of the truth means three chances for them to disagree. Do instead: pick one method and use it alone.
3. Auto-redirecting crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. by geoGenerative Engine Optimization (GEO) is the practice of optimizing content and brand presence so AI-powered search engines and assistants — Google AI Overviews, ChatGPT, Perplexity — cite, recommend, or mention you when generating answers. Google's position is that it's still SEO./IP. Why it’s wrong: GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. crawls mostly from the US, so a crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. geo-redirectA geo-redirect automatically sends a visitor to a location- or language-specific URL based on IP or browser signals — a UX/serving mechanism that's separate from, and can actively undermine, hreflang. can de-indexStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. your other regional clusters entirely — plus cloaking and EU anti-geoblocking exposure. Do instead: redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. (or better, banner-prompt) users only; never crawlers. Let bots reach every URL directly and let hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. carry the signal.
4. Pointing hreflang at non-canonical, redirected, or noindexed URLs.
Why it’s wrong: the return link resolves to a 301/404/noindexed page, so the
pair breaks (16.9% referenced broken/redirected pages, 8.0% non-canonical in my
study).
Do instead: each variant canonicalizes to itself; hreflang points only at live,
canonical, indexable URLs — regenerated whenever URLs change.
5. Relative or protocol-relative URLs.
Why it’s wrong: Google requires fully-qualified URLs; /foo and //example.com/foo
are invalid, and even absolute-but-mismatched forms (wrong slash/www/case) fail the
reciprocity match.
Do instead: always https://example.com/foo, matching the exact indexed form.
6. Trusting “View Page Source” as validation.
Why it’s wrong: JS-injected hreflang doesn’t appear in raw source, so you either
think it’s missing (it isn’t) or miss that it renders in the <body> (invalid).
Do instead: validate the rendered DOM via GSCA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. or a renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM.
crawler.
7. Wrong or invented locale codes.
Why it’s wrong: en-UK, jp, ger, and region-only codes are invalid and
ignored.
Do instead: ISO 639-1Two-letter language codes used in hreflang (en, es, de). language + optional ISO 3166-1 alpha-2Two-letter country codes used in hreflang region targeting (us, gb, au). region — en-GB,
ja, de, es-MX.
Before / after
1. Missing reciprocal tag (the classic). Before: the US page lists US + UK + DE, but the German page’s template only lists DE + US — it forgot the UK return link. Google drops the DE↔UK pair. After: the German page’s block lists DE + US + UK (all self-referencing and reciprocal). Regenerated from the locale table so it can’t drift again.
2. Relative URLs.
Before: <link rel="alternate" hreflang="de" href="/de/" /> — relative, so it’s
invalid and ignored.
After: <link rel="alternate" hreflang="de" href="https://example.com/de/" /> —
fully-qualified and matching the indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. form.
3. Wrong UK code.
Before: <link rel="alternate" hreflang="en-uk" href="https://example.com/uk/" />
— uk is Ukrainian; the annotation is invalid.
After: <link rel="alternate" hreflang="en-gb" href="https://example.com/uk/" />.
4. SitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. missing the namespace.
Before: a sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. using <xhtml:link> entries but with a <urlset> that only
declares the base sitemaps namespace — every <xhtml:link> is invalid.
After: <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"> — the xhtml namespace is declared, so
the annotations validate.
Ready-to-copy AI prompts
Adapt the placeholders, then paste into your assistant of choice. Always validate the output against a real crawl — an LLMA large language model (LLM) is a deep-learning model trained on massive text corpora to predict the next token and generate human-like text. LLMs use the transformer architecture and power AI search features like Google's AI Overviews (Gemini) and Bing Copilot (GPT-4). can generate plausible-but-wrong codes or miss a return link.
Generate an HTML <head> block from a locale matrix
I have these language/region page variants:
- en-US: https://example.com/us/
- en-GB: https://example.com/uk/
- de: https://example.com/de/
- global fallback / selector: https://example.com/
For EACH page above, output the complete hreflang <link> block that belongs in its
<head>. Every block must (a) self-reference, (b) list all other variants, and
(c) include an x-default pointing at the fallback. Use fully-qualified https URLs
exactly as given. Validate the codes as ISO 639-1 language + ISO 3166-1 alpha-2
region and flag any that look wrong.Convert the same matrix into an XML sitemapAn XML sitemap is a UTF-8 file listing the canonical URLs on your site (with optional lastmod) so search engines can discover and prioritize them. It's a discovery and diagnostic aid, not a guarantee of indexing — and Google ignores its priority and changefreq tags. block
Using the same variant list, output an XML sitemap that uses <xhtml:link> hreflang
annotations. Requirements: declare xmlns:xhtml="http://www.w3.org/1999/xhtml" on
<urlset>; give every <url> block a full self-referencing + all-alternates set; use
the exact URLs provided. Do not add any URL not in my list.Audit a pasted cluster for reciprocity + code errors
Here are the hreflang tags from each page in my cluster: [paste each page's URL and
its hreflang tags]. Check for: missing self-reference, missing reciprocal (A->B
without B->A), invalid ISO codes, relative/protocol-relative URLs, and any URL that
appears with inconsistent formatting (trailing slash / www / case). List each issue
with the exact page and tag it's on. Do not assume tags I didn't paste. Extraction, console, and generation snippets
Practical one-liners for building and checking hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others.. Adjust URLs before running.
Chrome DevTools Console — list the hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. tags on the current page Paste into the Console (F12 → Console) on any page to see what the browser actually rendered — this reflects JS-injected tags that “View Source” misses:
[...document.querySelectorAll('link[rel="alternate"][hreflang]')]
.map(l => ({ hreflang: l.hreflang, href: l.href,
inHead: !!l.closest('head') }));The inHead flag is the tell for the <head>-break bug: any tag showing
inHead: false is renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. in the <body> and is invalid.
Bookmarklet — same check, one click Save as a bookmark with this URL, then click it on any page:
javascript:(()=>{const t=[...document.querySelectorAll('link[rel="alternate"][hreflang]')].map(l=>`${l.hreflang} ${l.href} ${l.closest('head')?'(head)':'(BODY - INVALID)'}`);alert(t.length?t.join('\n'):'No hreflang tags found');})();XPath — select hreflang links inside the head (for a crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. / browser inspector)
//head/link[@rel='alternate' and @hreflang]If a crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. finds link[@hreflang] matches under //body instead, that’s the
head-break bug.
Regex — pull hreflang code + URL from raw HTML (quick grep, not a real parser)
<link[^>]*rel=["']alternate["'][^>]*hreflang=["']([^"']+)["'][^>]*href=["']([^"']+)["']Capture group 1 is the code, group 2 is the URL. Use only for a fast sanity grep — parse real HTML with a DOM library, not regex.
curl — check for hreflang in HTTP Link: response headers (the PDF/non-HTML case)
curl -sI https://example.com/file.pdf | grep -i '^link:'Python — generate a self-consistent hreflang <head> block from a matrix
variants = {
"en-us": "https://example.com/us/",
"en-gb": "https://example.com/uk/",
"de": "https://example.com/de/",
"x-default": "https://example.com/",
}
# Every page gets the SAME full block (self-reference + all alternates),
# which is exactly what satisfies reciprocity.
block = "\n".join(
f'<link rel="alternate" hreflang="{code}" href="{url}" />'
for code, url in variants.items()
)
print(block) Test yourself: Implementing hreflang
Five quick questions on building a hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. cluster correctly. Pick an answer for each, then check.
Resources worth your time
My related writing
- Hreflang: The Easy Guide for Beginners — my Ahrefs guide with all three methods, the nine common implementation issues and fixes, and the Google Sheets template for semi-automated hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. generation at scale.
- Over 67% of Domains Using Hreflang Have Issues — my study of 374,756 domains, the largest ever run, and the source of the error-rate breakdown (missing x-defaultx-default is the reserved hreflang value that points to a fallback URL — the page Google shows when a user's locale doesn't match any of your other hreflang tags. It is optional and does not mean \"English.\" 56.3%, missing self-reference 18.0%, broken/redirected targets 16.9%, missing reciprocal 15.3%, non-canonical 8.0%, bad codes 4.6%).
My speaking
- International SEO: The Weird Technical Parts — Pubcon Vegas 2019 — the richest implementation source: the
<head>-break bug (tags forced into<body>by iframesHTML element that displays one webpage inside another — how embeds work./malformed markup) and DOM-breakpoint debugging, why “sitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. are faster” is a myth, the geoGenerative Engine Optimization (GEO) is the practice of optimizing content and brand presence so AI-powered search engines and assistants — Google AI Overviews, ChatGPT, Perplexity — cite, recommend, or mention you when generating answers. Google's position is that it's still SEO.-redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. de-indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. risk, and the&hl=/&gl=SERP-check technique. - Hreflang Study and Interesting Issues — Brighton SEO 2023 — the deck behind the study, plus Google’s most-specific matching order (language+country → language → x-defaultx-default is the reserved hreflang value that points to a fallback URL — the page Google shows when a user's locale doesn't match any of your other hreflang tags. It is optional and does not mean \"English.\") and the most common code mistakes across the dataset.
- You’re Going To Screw Up International SEO — Pubcon Vegas 2017 — the ecosystem of implementation chaos: tools reporting wrong info, content served from URLs that differ from what’s indexed, duplicate-page traps.
From around the industry
- Google’s Localized versions of your pages — the primary implementation doc; the exact syntax for all three methods, the reciprocity/self-reference rules, valid codes, and the absolute-URL requirement. Read it in full before you build.
- Google’s Managing multi-regional and multilingual sites — URL-structure options and the auto-redirect / cloaking warning behind “redirect users, not crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index..”
- WPML — Using WordPress SEO (Yoast) with WPML — how WordPress actually outputs hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. (Yoast alone doesn’t), and the head-vs-sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. output setting.
- Shopify — Add hreflang tags in your theme — the manual
theme.liquid<link>pattern for when Shopify Markets’ language-only tags aren’t specific enough. - Screaming Frog — How To Audit & Test Hreflang — the crawl-based workflow for confirming reciprocity across a whole cluster rather than spot-checking one URL.
- Google Reminds That Hreflang Tags Are Hints, Not Directives — Search Engine Journal, May 2025, on Mueller’s same-language-consolidation clarification (why a technically perfect cluster can still be consolidated).
- r/TechSEO — the community for debugging broken hreflang clusters.
Prove the hreflang cluster actually shipped
HreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. fails silently: the tags can be present, well-formed, and still ignored if the return leg is missing. “It’s in the code” is not the test — reciprocity across the whole cluster is. Run these after you deploy a language/region set.
Test 1 — Every pair returns the tag (reciprocity)
- Test to run — Crawl the whole cluster with returntag - hreflang checker (it checks that every page A points to actually points back at A), or run Screaming Frog’s hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. report across the set.
- Expected result — 0 non-reciprocal pairs and every URL self-references. Zero errors, not “a few.”
- Failure interpretation — A one-way pair (A → B but B doesn’t → A) means Google drops that pair — the most common real-world failure, and invisible if you only spot-check one URL’s view-source.
- Monitoring window — Immediate for the rendered tags; the checker reads what’s live now.
- Rollback trigger — Any non-reciprocal pair, or a tag pointing at a URL that 301s or 404s — fix the source of truth and redeploy before waiting on Google.
Test 2 — Google is processing it cleanly
- Test to run — Google retired the old International Targeting report in Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. in September 2022, so don’t rely on it — check Page IndexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. for each locale in the cluster, and confirm via URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. on a sample of pages that the “Google-selected canonicalA Google Search Console Page Indexing status: you declared a canonical for this URL, but Google overrode your choice, picked a different page as the canonical, and indexed that one instead.” and indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. status line up with what you expect for that locale.
- Expected result — Each locale’s intended pages are indexed (not “Duplicate, Google chose different canonical” in a way that collapses distinct language versions into one), and URL Inspection shows the alternate you expect.
- Failure interpretation — Pages showing up as duplicates of a different locale’s canonical, or clustered/consolidated indexing, usually traces back to a broken return leg (re-check Test 1) rather than hreflang itself — hreflang is a hint, not a directive, so a technically perfect cluster can still be consolidated if Google judges the content near-duplicateThe same or very similar primary content reachable at more than one URL. There's no general duplicate content penalty — the real costs are possible signal dilution, the wrong URL getting chosen, and less-efficient crawling..
- Monitoring window — 2–4 weeks — Search ConsoleGoogle's free tool for monitoring crawling, indexing, and search performance. re-crawls and reports the cluster over time, not instantly.
- Rollback trigger — A locale’s pages consistently indexing under the wrong canonical, or the wrong regional URL surfacing for a query — re-audit reciprocity first; don’t assume the tags “aren’t working” when the return leg is the actual gap.
Build-time retrieval analysis plus live signals for this exact article. The automatic chunk report includes a deterministic readiness score and is ready without a model download.
Search Console
sampleGA4 traffic (28d)
sampleCloudflare traffic (7d)
sampledCrUX field data (28d, phone)
sampleGoogle NLP entities
localChangelog
Revision history
Compare the published article with an archived editorial snapshot. Added and removed words are shown only after you open a comparison.
Updated Jul 26, 2026.
Editorial summary and recorded change details.Summary
Added an inspectable Before / Fixed reciprocal hreflang cluster.
Change details
-
Compared a one-way two-locale annotation with a complete cluster in which both pages self-reference and return the same alternate relationship.
Updated Jul 25, 2026.
Editorial summary and recorded change details.Summary
Aligned legacy tool display names with returntag - hreflang checker and Scout Site Audit Free.
Change details
-
Updated the linked tool names to match their current public labels.
Full comparison unavailable — no prior snapshot was archived for this revision.
Updated Jul 18, 2026.
Editorial summary and recorded change details.Summary
Corrected the validation workflow's dependence on Search Console's retired International Targeting report and filled three verified gaps against Google's own hreflang documentation: the HTML attribute-mixing rule, the HTTP header's every-response full-set invariant, and sitemap xhtml:link order/URL-limit behavior.
Change details
-
Test 2 in the Validation Tests lens no longer points readers at the removed Legacy tools & reports → International Targeting report; it now uses Page Indexing plus URL Inspection to confirm each locale indexes under its own canonical.
-
Method 1 (HTML link tags) now states Google's rule against mixing hreflang with other alternate attributes like media on the same link element.
-
Method 2 (HTTP headers) now states the every-response full-set invariant explicitly.
-
Method 3 (XML sitemap) now notes that xhtml:link child order doesn't matter and those children don't count toward the sitemap's 50,000-URL limit.
Full comparison unavailable — no prior snapshot was archived for this revision.