Guide : How to Implement Hreflang (Step by Step)
Working code pour tout three hreflang méthodes — HTML head tags, HTTP Lien headers, and XML sitemap annotations — plus the syntax rules, at-scale CMS automation, and the validation workflow to confirmer it en réalité shipped correctement.
Langues
1 indice probant sur cette page
- Outil en ligne associéreturntag - hreflang checker
Là are exactly three façons to ajouter hreflang — HTML lien tags in the head, HTTP Lien réponse headers (pour non-HTML fichiers comme PDFs), or xhtml:lien entries in an XML sitemap (meilleur at scale). Pick un; Google treats tout three as equivalent and there's aucun benefit to combining les. Every méthode obeys the même two non-negotiable rules: self-reference (chaque page listes itself) and reciprocity (si A points to B, B doit 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 tout from a unique source of truth, alors validate the rendered head, pas simplement view-source — in my study of 374 756 domains, over 67% of hreflang setups had au moins un problème.
TL;DR — Là are three façons to ajouter hreflang: petit
<link>tags in votre page’s<head>, aLink:header votre serveur sends, or entries in votre XML sitemap. Vous seulement pick un. Whichever vous pick, two rules jamais modifier: every page listes itself, and every page vous lien to has to lien back — or Google ignores the whole définir. Alors vous vérifier que the tags en réalité montrer up in lune page the façon vous meant les to.
Commencer ici: you’ve déjà decided vous besoin hreflang
Ce is the how-to. Si you’re encore pas certain si vous besoin hreflang or ce que it fait, lire the hreflang overview premier — ce page assumes vous know vous have multiple language or country versions of une page and vous simplement vouloir to construire the chose correctement.
The three façons to ajouter it (pick un)
- HTML
<link>tags in the<head>. Vous ajouter a few lines to the top of chaque page’s HTML. Easiest to comprendre, easiest to voir, bon pour plus petit sites. - HTTP
Link:headers. The même information, sent by votre serveur in the réponse au lieu de in the HTML. Ce is the seulement option pour fichiers que aren’t HTML — comme a PDF, qui has aucun<head>to put tags in. - XML sitemap. Vous liste tout the language versions à l’intérieur votre sitemap fichier au lieu de on chaque page. Meilleur pour big sites, parce que vous don’t have to touch every page — the whole map lives in un placer.
Google treats tout three the même. There’s aucun “faster” or “stronger” un, and là is aucun benefit to en utilisant plus que un at a temps — que simplement donne vous plus places pour choses 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 versionsCe que the HTML version semble comme
Dire vous have a US English page, a UK English page, a German page, and a global homepage que lets personnes choisir. 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/" />Lire chaque line as: “there’s an alternate version of ce page, it’s pour ce
language/region, and it lives at ce adresse.” The x-default line is votre
fallback pour anyone whose language doesn’t match the others.
Two choses to notice, parce que they’re the two rules que faire hreflang fonctionner:
- The US page listes itself (que premier
en-usline points at the US page you’re déjà on). - Every autre page in the définir has to carry the même block pointing back. The UK page, the German page, and the homepage tout besoin leur propre version of ces four lines.
The two rules, in plain terms
- Every page points back. Si votre US page liens to votre German page, the German page has to lien to the US page. Miss que retourner lien and Google throws the pair out. Ce is the rule personnes break la plupart.
- Every page points to itself. Chaque version listes its propre URL in the définir. Google calls ce optional but bon pratique — do it anyway, it garde everything consistent.
Utiliser réel, complet web addresses
Toujours utiliser the complet adresse, starting with https://. Pas /us/, pas
//example.com/us/ — the whole chose, https://example.com/us/. And it has to
match the exact adresse Google en réalité indexes: même protocol, même www (or
pas), même trailing slash, même capitalization.
Obtenir le codes correct
Le 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 en réalité signifie Ukrainian) and jp pour Japanese (it’s ja).
Alors vérifier que it worked
The la plupart important chose beginners miss: après vous ship, en réalité regarder at the
rendered page to confirmer the tags are là and in the <head>. Si votre tags are
ajouté by JavaScript, ils pourrait pas montrer up quand vous “View Page Source” but va
montrer up in the live page. Recherche Google Console’s Inspection d’URL peut montrer vous ce que
Google en réalité rendered.
Vouloir complet code pour the header and sitemap méthodes, how to automate ce à travers a whole CMS, the exact validation steps, and the mistakes que quietly break clusters? Switch to the Avancé tab.
TL;DR — Three méthodes, pick un: HTML
<link>tags in the<head>, HTTPLink:headers (the seulement option pour non-HTML fichiers comme PDFs), or<xhtml:link>entries in an XML sitemap (meilleur at scale — un machine-generated fichier, easiest to QA). Google dit the three are equivalent and there’s aucun benefit to combining les. Every méthode obeys self-reference + reciprocity, uses absolute URLs, and uses ISO 639-1 language + optional ISO 3166-1 alpha-2 region codes. Generate the whole chose from un source of truth — hand-maintained hreflang rots. Alors validate the rendered head, explorer the whole cluster pour reciprocity, and garder re-checking après every URL modifier. Do pas auto-redirect robots d’exploration by geo.
Avant vous écrire a line of code: three decisions
1. Qui méthode. Google is explicit que the choice is à propos de convenience, pas performances — “The three méthodes are equivalent from Google’s perspective and vous peut choisir the méthode that’s the la plupart convenient pour votre 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 (vous have aucun autre option — there’s aucun<head>in a PDF). - Nombreux locales, an existing sitemap pipeline, or a headless/JAMstack setup → XML sitemap, generated programmatically.
The Decision Trees lens walks ce as an réel flowchart.
2. Un source of truth. Whatever méthode vous pick, the annotations devrait be generated from un placer — a locale/translation table in votre database, a CMS relationship field, or (pour petit sites) a unique spreadsheet. The unique worst hreflang anti-pattern is hand-maintaining tags par page. The moment un locale’s template drifts, retourner liens go manquant and pairs obtenir dropped.
3. Ne faites pas combine méthodes. Vous peut run tout three; Google dit there’s aucun benefit, and every supplémentaire méthode is un autre surface pour the three copies to disagree with chaque autre.
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 guidelinesMéthode 1 — HTML <link> tags in the <head>
The syntax, verbatim from Google, is:
<link rel="alternate" hreflang="lang_code" href="url_of_page" />A complet working définir pour 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/" />Que exact block goes on every page in the cluster (the US page, the UK page, the German page, and the homepage) — chaque un inclut its propre self-referencing line. That’s ce que satisfies reciprocity.
Placement is a hard rule. Google: “The <link> tags doit be à l’intérieur a
well-formed <head> section of the HTML.” And leur propre troubleshooting advice:
“Si in doubt, paste code from votre rendered page into an HTML validator to garantir
que the liens are à l’intérieur the <head> element.”
Ce matters plus que it sounds, parce que of a échec mode la plupart written guides
skip: hreflang tags peut be forced out of the <head> and into the <body>,
où they’re invalid. In my Pubcon Vegas 2019 deck
I flagged ce directement — tags can’t legitimately live in the corps (que voudrait let
un site hijack another’s alternates), but a malformed or injected <p> tag, or an
iframe, peut prematurely fermer the <head> so que everything après it — notamment
votre hreflang — renders à l’intérieur the <body>. The tag is technically présent in
source but silently invalid. The fastest façon to debug it is navigateur DOM
breakpoints: watch où the tags en réalité land in the rendered DOM, alors walk
back to the markup que broke the <head>.
Quand HTML tags faire sense: small-to-medium sites with a manageable number of
locales, où the per-page <link> block doesn’t balloon. On a site with dozens
of locales, every page carries a grand block of markup — qui is un raison big
sites lean on le sitemap méthode.
Don’t mix hreflang with autre alternate attributes on the même
<link> element. Google’s guidance is explicit que a <link rel="alternate">
carrying hreflang shouldn’t aussi carry an unrelated alternate attribute comme
media in the même tag — si vous besoin les deux a language/region alternate and a
media-query alternate pour the même URL, that’s two separate <link> elements,
pas un combined un. Mixing les is an facile façon to fin up with a tag Google
can’t parse as soit.
Méthode 2 — HTTP Link: headers
Même information, sent in the HTTP réponse au lieu de 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"Remarque the angle brackets autour chaque URL, the semicolon-separated attributes, and the comma separating chaque alternate. Every URL in the header is comma-appended.
Quand vous besoin ce: non-HTML resources. A PDF, a .doc, an image served
directement — none of les have a <head> to hold <link> tags, so the header is
votre seulement façon to attach hreflang to les.
Configuration considerations: vous définir ces headers at le serveur or CDN couche
(an Apache Header directive, an Nginx add_header, a Cloudflare/Fastly/CloudFront
response-header rule, or votre application’s réponse). Parce que the header is définir by
infrastructure plutôt que per-document markup, the reciprocity rule is facile to
break ici — the English PDF’s header and the German PDF’s header are usually
configuré separately, so it’s on vous to assurez-vous chaque un listes the whole définir,
itself inclus. Garder the header generation driven by the même locale table as votre
HTML/sitemap approach.
The invariant to hold onto: every alternate réponse carries the identical complet définir, every temps. It’s pas suffisant pour the English PDF’s header to liste the German alternate — the German PDF’s réponse has to carry the exact même définir back (itself plus every autre alternate), on every unique réponse, pas simplement the premier un a robot d’exploration se produit to hit. Treat the header as generated output, pas a one-off vous définir and forget.
Méthode 3 — XML sitemap <xhtml:link> annotations
At scale, ce is usually the correct appel: the whole cluster lives in un (or a few)
machine-generated fichiers, nothing bloats chaque page’s <head>, and — parce que the
entier relationship graph is in un placer — it’s by far the easiest méthode 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 choses que trip personnes up in le sitemap méthode:
- The namespace declaration is mandatory. Que
xmlns:xhtml="http://www.w3.org/1999/xhtml"on the<urlset>element n’est pas optional decoration — omit it and every<xhtml:link>in the fichier is invalid. - Every
<url>block doit be self-complete. Notice que les deux<url>blocks ci-dessus liste les deux alternates, notamment leur propre<loc>. Chaque<url>entry carries the complet définir (self-reference + tout alternates). Reciprocity in a sitemap is simplement “every URL’s block lists every URL in the cluster, itself included.”
Two behaviors worth knowing so vous don’t over-engineer the generator: the order
of the <xhtml:link> children à l’intérieur a <url> block doesn’t matter to Google —
don’t waste temps sorting les — and ceux <xhtml:link> annotations don’t count
contre votre sitemap’s 50 000-URL-per-file limite, since they’re children of a
<url> entry, pas separate <url> entries themselves.
Generating it programmatically. The whole point of le sitemap méthode is que
it’s a byproduct of votre CMS’s propre translation données. Si votre CMS déjà knows
que /english/page.html and /deutsch/page.html are translations of chaque autre,
votre sitemap generator devrait walk que relationship table and emit the
<xhtml:link> blocks at construire temps (or at sitemap-request temps). Do que and
hreflang can’t drift out of sync with reality — it’s regenerated from the source of
truth every temps, and ajout a locale is a données modifier, pas a hand-edit à travers
hundreds of pages.
Pour teams sans dev resources, I construit a lightweight Google Sheets template in my Ahrefs hreflang guide: a Setup tab (pick a par défaut language plus up to four variants), a URLs tab (paste chaque language’s URLs into columns), and a Results tab que auto-generates le sitemap XML block pour vous. It’s the “single source of truth” idea made concrete pour sites aussi petit to justify a réel CMS integration.
The rules que appliquer aucun matter qui méthode vous pick
Ces are method-agnostic and non-negotiable.
- Self-reference. Every page (or every
<url>block, or every header) listes itself. Mueller frames ce as optional-but-good-practice, but skipping it was présent in 18,0% of the domains in my study — automate it and it costs nothing. - Reciprocity. “Chaque language version doit liste itself as bien as tout autre language versions.” And the enforcement: “Si two pages don’t les deux point to chaque autre, the tags va be ignored. Ce is so que someone on un autre site can’t arbitrarily créer a tag naming itself as an alternative version of un of votre pages.” Un manquant retourner lien drops the pair.
- Absolute, fully-qualified URLs. “Alternate URLs doit be fully-qualified,
notamment the transport méthode (http/https)” — so
https://example.com/foo, jamais//example.com/fooor/foo. And l’URL doit match the exact formulaire Google indexes: protocol,www, trailing slash, and cas tout have to line up, or the return-link match fails.
Getting le codes correct
“The premier code of the hreflang attribute is the language code (in ISO 639-1
format) followed by an optional second code que represents the region code (in ISO
3166-1 Alpha 2 format).” Combine les with a dash: en-US. Vous pouvez target a
language on its propre (es = Spanish everywhere), but vous ne peut pas target a region
on its propre — there’s toujours a language premier.
The mistakes I voir la plupart souvent (and saw à travers the study dataset):
en-UKau lieu deen-GB—ukis Ukrainian, the UK’s region code isgb.jpau lieu dejapour Japanese,cnau lieu dezhpour Chinese.- Three-letter codes (
ger,eng) où two-letter ISO 639-1 is requis. - En utilisant
EU,UN, orUKas region codes — none are valid ISO 3166-1 alpha-2 targets.
x-default is the reserved valeur pour the fallback — a language selector or an
auto-redirecting home page que sert utilisateurs who match none of votre explicit
locales:
<link rel="alternate" href="https://example.com/" hreflang="x-default" />It’s pas mandatory. It was the unique most-missing element in my study (56,3% of
domains omitted it), but a manquant x-default doesn’t break the cluster the façon a
manquant reciprocal tag fait — Google simplement falls back to its propre language/region
detection pour unmatched utilisateurs. Ajouter it anyway; it’s a checklist item, pas a
cluster-breaker. (There’s a dedicated x-default subtopic in ce cluster.)
Implementing at scale — CMS and platform approaches
WordPress. Yoast SEO fait pas generate hreflang on its propre. To en réalité
output tags vous besoin a multilingual plugin — WPML or Polylang. WPML
auto-generates hreflang pour every page que has translations, adds an x-default
pointing at votre default-language version, and by par défaut injects the annotations
into the XML sitemap; there’s a setting sous WPML → Languages → SEO Options
(“Display alternative languages in the HEAD section”) si vous vouloir head-tag output
au lieu de, or en outre to, le sitemap. (Voir WPML’s docs on en utilisant it with
Yoast.)
Shopify. Shopify Markets automatically generates mutually-linked hreflang
tags une fois you’ve configuré markets/languages and le contenu is publié and
lié in navigation — qui removes the la plupart courant échec mode (manquant
reciprocal liens) by design. The catch: Markets’ automatic tags are souvent
language-only (fr, de) plutôt que language-region (fr-FR, fr-CA), qui
under-serves brands que besoin regional specificity — French pour France vs. Canada
vs. Belgium. Pour que vous drop to manual <link> tags in theme.liquid (Shopify’s
propre theme hreflang docs
montrer the pattern) or an app — and faites attention, parce que mixing automatic Markets
tags with manual/app tags is a documented source of conflicts. Pick un.
Custom / headless / enterprise. Generate the annotations from votre translation-relationship table at construire or serve temps, as décrit in le sitemap section ci-dessus. Ce is the même “single source of truth” principle — hreflang becomes a computed output of données votre CMS déjà holds, pas a hand-maintained artifact que peut rot.
Implementation mistakes que break the cluster
Auto-redirecting by geo/IP. Ce is a separate échec from syntax errors and it’s worse. Si vous redirection visitors — and surtout robots d’exploration — to a version fondé on perceived emplacement, vous pouvez de-index entier regional clusters, parce que Googlebot mostly crawls from the US. As I put it in que Pubcon deck: a geo-redirect “voudrait redirection moteur de recherches to où ils explorer from. Google pour instance mostly crawls from the US so we voudrait effectively de-index tout geo pages.” There’s a regulatory angle aussi — potential exposure sous EU anti-geoblocking rules. The correct pattern is redirection utilisateurs, jamais robots d’exploration: detect and (optionally) redirection human visitors, but toujours let bots reach every URL variant directement, with hreflang doing the réel routing signal. Google’s propre multi-regional guidance recommends a non-intrusive suggestion banner over automatic redirection pour exactly ce raison.
Pointing hreflang at non-canonical, redirigé, or noindexed URLs. Si a locale’s
URL changements and the redirection goes in but the hreflang encore points at the old URL,
votre cluster now références a 301 or a 404 (16,9% of domains in my study
referenced broken/redirigé pages). Similarly, chaque variant devrait canonicalize to
itself; pointing hreflang at une URL that’s canonicalized away, or at a noindexed
page, breaks the retourner lien (8,0% pointed at non-URL canoniques).
Inconsistent URL formats. The hreflang URL and the indexé URL have to be
byte-identical in formulaire — trailing slash, www, protocol, and cas tout inclus. A
mismatch ici is a silent reciprocity échec.
Validating votre implementation après launch
View rendered source, pas simplement raw source. Si votre hreflang is injected by
client-side JavaScript, curl or Ctrl+U (“View Page Source”) va montrer nothing —
but the tags exist in the rendered DOM. Confirmer with GSC Inspection d’URL → “Tester Live
URL” → “View Testé Page,” or a rendering-capable robot d’exploration. Ce is the unique la plupart
courant raison someone dit “my tags are missing” quand they’re en réalité fine (or the
reverse — présent in source but broken parce que ils render in the <body>).
Explorer the whole cluster, don’t spot-check un URL. Reciprocity is a relationship entre pages, so checking un page indique vous almost nothing. Run a robot d’exploration à travers the whole cluster — Screaming Frog’s hreflang audit or Ahrefs Site Audit — to catch manquant retourner tags, non-canonical targets, and broken références at scale. Ahrefs Site Audit’s Hreflangs tab draws the cluster as a graph with broken liens in red, qui is far easier to raison à propos de que a CSV.
Vérifier réel SERPs with &hl= and &gl=. Append the host-language (&hl=) and
geolocation (&gl=) parameters to a Recherche Google URL to preview ce que a donné
locale’s results en réalité regarder comme, plutôt que guessing from votre propre emplacement.
Validation n’est pas a one-time step. Nouveau locales, URL/redirection changements, and dev/staging config bleeding into production are the recurring causes of post-launch breakage. Construire hreflang checks into regression tests and recurring crawls, pas simplement a launch-day QA réussir. My framing from the talks: “quelconque number of choses peut break from masking to choses carrying over from dev/tester/staging environments.”
Myths worth retiring
- “Sitemaps process faster than HTML tags.” Faux. Les deux are resolved at explorer temps — I’ve debunked ce directement. Le sitemap’s advantage is maintainability and QA, pas speed.
- “Yandex doesn’t support hreflang in sitemaps.” Faux — Yandex’s propre documentation confirms sitemap hreflang prise en charge.
- “Use all three methods for extra signal.” Aucun benefit per Google, and it simplement multiplies inconsistency risk.
- “A missing
x-defaultbreaks the cluster.” Faux — it’s optional; Google falls back to its propre detection. - “Wrong hreflang gets you penalized.” Faux — it’s a hint, pas a directive. Broken hreflang is ignored, pas penalized.
Où to go suivant
Ce article is the how-to depth sous the hreflang hub — the hub covers ce que hreflang is, pourquoi reciprocity matters, and ce que Bing fait à la place. The x-default subtopic goes deep on the fallback valeur. Pour the strategy ce implements, voir the International SEO pillar — hreflang is the technical couche, pas a substitute pour genuine localization.
AI summary
A condensed prendre on the Avancé version:
- Three méthodes, pick exactly un (Google treats les as equivalent; aucun benefit
to combining):
- HTML
<link>tags in the<head>— petit/medium sites; doit be in a well-formed<head>, jamais the<body>; don’t mixhreflangwith un autre alternate attribute commemediaon the même<link>element. - HTTP
Link:headers — the seulement option pour non-HTML fichiers (PDFs); définir at server/CDN; every alternate réponse doit carry the identical complet définir, every temps. - XML sitemap
<xhtml:link>— meilleur at scale; nécessite thexmlns:xhtml="http://www.w3.org/1999/xhtml"namespace on<urlset>; easiest to QA parce que the whole graph is in un fichier; child order doesn’t matter and ces children don’t count toward the 50 000-URL sitemap limite.
- HTML
- Two universal rules: self-reference (chaque page listes itself) and reciprocity (A→B exige B→A, or the pair is ignored). Utiliser absolute, fully-qualified URLs que match the exact indexé formulaire.
- Codes: ISO 639-1 language + optional ISO 3166-1 alpha-2 region (
en-GB, pasen-UK;ja, pasjp).x-defaultis the reserved fallback — optional but the most-missed element (56,3% in my study). - Automate from un source of truth. WordPress nécessite WPML/Polylang (Yoast alone ne fait pashing); Shopify Markets auto-generates reciprocal tags but souvent language-only; custom/headless devrait emit hreflang from the translation table.
- Don’t auto-redirect robots d’exploration by geo — Googlebot crawls mostly from the US, so it peut de-index regional clusters; redirection utilisateurs, jamais bots.
- Validate the rendered head, pas simplement view-source (JS-injected tags won’t montrer
in source); explorer the whole cluster pour reciprocity; vérifier locales with
&hl=/&gl=; re-check après every URL modifier.
Documentation officielle
Primary-source documentation pour implementing hreflang.
- Localized versions of votre pages — the principal implementation doc: tout three méthodes 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-redirect / cloaking warning (pourquoi vous doit pas geo-redirect robots d’exploration).
- Tell Google à propos de localized versions (x-default blog, 2013) — the original introduction of
x-default. - International Targeting report deprecation (Sept 2022) — the old report is gone; hreflang tags encore fonctionner.
Bing / Microsoft
- Bing Webmaster Guidelines — Bing’s guidance; remarque Bing leans on
content-languageand<html lang>over hreflang. - Bingbot Series: Maximizing Explorer Efficiency — context on how Bing handles international/multilingual sites.
CMS / platform
- WPML — En utilisant WordPress SEO (Yoast) with WPML — how WPML outputs hreflang (head vs. sitemap setting).
- Shopify — Ajouter hreflang tags in votre theme — the manual
theme.liquid<link>pattern.
Quotes from the source
On-the-record statements relevant to implementation. Chaque Google-docs lien is a deep lien que jumps to the quoted passage on the live page.
Google — the three méthodes
- “The three methods are equivalent from Google’s perspective and you can choose the method that’s the most convenient for your site.” — Recherche Google Central docs. Jump to quote
Google — placement
- “The
<link>tags must be inside a well-formed<head>section of the HTML.” — Recherche Google Central docs. Jump to quote
Google — the two rules
- “Each language version must list itself as well as all other language versions.” — Recherche Google Central docs. Jump to quote
- “If two pages don’t both point to each other, the tags will be ignored.” — Recherche Google Central docs. Jump to quote
- “Alternate URLs must be fully-qualified, including the transport method (http/https).” — Recherche Google Central docs. Jump to quote
Google — codes
- “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).” — Recherche Google Central docs. Jump to quote
John Mueller, Google — it’s a hint, pas a directive
- On self-referential tags: hreflang self-references are reported as optional but bon pratique. — John Mueller, Google, relayed via my Ahrefs hreflang guide.
- On correctness pas guaranteeing outcome (May 2025, Bluesky): Mueller noted que hreflang doesn’t guarantee indexation, so a variant may simply pas be indexé, and que same-language variants (comme
fr-frandfr-be) are commonly consolidated. — relayed via Moteur de recherche Journal coverage.
Qui implementation méthode devrait I utiliser?
Fonctionner top to bottom and arrêter at the premier match.
1. Are lune pages non-HTML fichiers (PDFs, docs, images served directement)?
→ Yes → HTTP Link: headers. Ils have aucun <head>, so ce is votre seulement
option. Définir the header at le serveur/CDN, listing the whole définir on chaque fichier.
→ Aucun → continuer.
2. Do vous have plus que a handful of locales, an existing sitemap pipeline, or a
headless/JAMstack construire?
→ Yes → XML sitemap <xhtml:link>. Generate it programmatically from votre
translation table. Un machine-generated fichier, aucun per-page markup, easiest to QA.
→ Aucun → continuer.
3. Petit/simple site, few locales, and you’d plutôt garder everything visible on the
page?
→ HTML <link> tags in the <head>. Simplement assurez-vous the block is generated from
un source of truth and lands à l’intérieur a well-formed <head>.
Whatever vous pick: utiliser it alone. Google dit there’s aucun benefit to combining méthodes, and every supplémentaire copy is a placer pour the three to disagree.
Do I besoin x-default?
Do vous have une page que sert utilisateurs who match none of votre explicit locales — a
country/language selector, or a global homepage?
→ Yes → ajouter x-default pointing at que fallback page.
→ Aucun → vous pouvez skip it. It’s optional; Google falls back to its propre detection. It
won’t break the cluster (unlike a manquant reciprocal tag). Ajout it is encore bon
pratique — it was the unique most-missed element in my study (56,3%).
Devrait I auto-redirect utilisateurs by emplacement?
Are vous thinking à propos de redirecting fondé on IP/geo? → Redirection human visitors seulement, and préférer a non-intrusive banner over a hard redirection. → Jamais redirection robots d’exploration by geo. Googlebot mostly crawls from the US, so a robot d’exploration geo-redirect peut de-index votre autre regional versions — and it risks cloaking classification and EU anti-geoblocking exposure. Let bots reach every URL variant directement; hreflang fait the routing signal.
Qui CMS chemin s’applique to me?
- WordPress? → Yoast alone ne fait pashing. Install WPML or Polylang; ils emit hreflang (choisir head vs. sitemap output in WPML’s SEO settings).
- Shopify? → Markets auto-generates reciprocal tags — but souvent language-only.
Besoin
fr-FRvsfr-CA? Ajouter manualtheme.liquidtags or an app, and don’t mix the two (conflict risk). - Custom / headless? → Emit
<xhtml:link>(or head tags) from votre translation-relationship table at construire/serve temps.
SOP: Ship a hreflang cluster from scratch
A repeatable procedure pour ajout a nouveau hreflang cluster (or a nouveau locale to an existing un). Run it top to bottom.
1. Construire the locale matrix (unique source of truth).
Liste every URL and its language-region code in un placer — a database table, a CMS
translation field, or a spreadsheet. Confirmer every URL is the canonical, indexé
formulaire (correct protocol, www, trailing slash, cas). Ce table is the input to
everything ci-dessous; nothing obtient hand-typed downstream.
2. Pick un méthode en utilisant the Decision Trees lens. Ne faites pas combine méthodes.
3. Generate the annotations from the matrix.
- HTML: emit the
<link>block into chaque page’s<head>from the matrix. - Sitemap: emit chaque
<url>block with thexmlns:xhtmlnamespace on<urlset>. - Headers: emit the
Link:header from the matrix at le serveur/CDN.
4. Vérifier the two rules programmatically avant publishing. Every entry doit (a) inclure a self-reference and (b) liste every autre entry in the cluster. Confirmer reciprocity: pour chaque A→B, there’s a matching B→A.
5. Ajouter x-default si vous have a selector or global fallback page.
6. Publish, alors validate the rendered output (voir the Playbooks lens pour the
detailed validation runbook): rendered head (pas view-source), a full-cluster explorer
pour reciprocity, and a &hl=/&gl= SERP spot-check.
7. Wire it into ongoing checks. Ajouter a recurring explorer / regression tester so a future URL modifier or nouveau locale can’t silently rot a retourner tag. Validation n’est pas a one-time task.
Quand ajout a locale plus tard: vous seulement edit the matrix (step 1) and re-run steps 3–6. Si you’re hand-editing individual pages to ajouter a locale, votre source of truth is incorrect — fix que premier.
Playbook: “My hreflang isn’t working” — validation runbook
Run ces in order. Chaque step soit trouve the break or clears a suspect.
Step 1 — Confirmer the tags en réalité render. Ouvrir lune page and view the rendered DOM (GSC Inspection d’URL → Tester Live URL → View Testé Page, or a rendering robot d’exploration). Do pas rely on Ctrl+U “View Page Source” — si hreflang is JS-injected it won’t apparaître là même though it’s live.
- Tags présent in rendered head → go to Step 3.
- Tags manquant from rendered head → Step 2.
Step 2 — Are the tags in the <head> or the <body>?
Si the tags exist in source but sit à l’intérieur <body>, they’re invalid. A malformed or
injected <p> tag or an iframe probable closed the <head> early. Utiliser navigateur DOM
breakpoints to trouver où the <head> breaks, fix que markup, re-check.
Step 3 — Vérifier l’URLs are absolute and canonical.
Every href doit be fully-qualified (https://…) and byte-identical to the indexé
formulaire (protocol, www, trailing slash, cas). Confirmer none point at a 301, 404,
noindexed, or canonicalized-away URL.
Step 4 — Vérifier reciprocity à travers the whole cluster. Explorer the entier cluster (Screaming Frog / Ahrefs Site Audit). Pour every A→B, vérifier a matching B→A exists, and que chaque page self-references. Ce is où la plupart breaks live — a unique manquant retourner tag drops the pair.
Step 5 — Validate le codes.
Confirmer ISO 639-1 language + ISO 3166-1 alpha-2 region. Regarder specifically pour
en-UK (→ en-GB), jp (→ ja), three-letter codes, and region-only codes.
Step 6 — Rule out geo-redirects. Confirmer robots d’exploration aren’t being geo-redirected. Si Googlebot (exploration from the US) obtient bounced to votre US version, votre autre regional URLs may jamais be reached.
Step 7 — Reset expectations si the cluster is technically correct.
Si everything ci-dessus checks out and same-language variants (e.g. fr-fr / fr-be)
are encore consolidated in reporting, that’s attendu — Google peut consolidate
near-identical same-language variants regardless of implementation. It’s a hint, pas
a directive; incorrect or ignored hreflang n’est pas a penalty. Arrêter chasing it as a bug.
Implementation anti-patterns
Concrete mistakes, pourquoi they’re incorrect, and Que faire à la place.
1. Hand-maintaining hreflang par page. Pourquoi it’s incorrect: the moment un template or locale drifts, retourner tags go manquant and pairs obtenir dropped — reciprocity rot at scale. Do à la place: generate every annotation from un source of truth (translation table, CMS field, or the Sheets template pour petit sites), so the whole cluster is regenerated, pas edited.
2. En utilisant tout three méthodes pour “extra signal.” Pourquoi it’s incorrect: Google dit there’s aucun benefit, and three copies of the truth signifie three chances pour les to disagree. Do à la place: pick un méthode and utiliser it alone.
3. Auto-redirecting robots d’exploration by geo/IP. Pourquoi it’s incorrect: Googlebot crawls mostly from the US, so a robot d’exploration geo-redirect peut de-index votre autre regional clusters entirely — plus cloaking and EU anti-geoblocking exposure. Do à la place: redirection (or meilleur, banner-prompt) utilisateurs seulement; jamais robots d’exploration. Let bots reach every URL directement and let hreflang carry the signal.
4. Pointing hreflang at non-canonical, redirigé, or noindexed URLs.
Pourquoi it’s incorrect: the retourner lien resolves to a 301/404/noindexed page, so the
pair breaks (16,9% referenced broken/redirigé pages, 8,0% non-canonical in my
study).
Do à la place: chaque variant canonicalizes to itself; hreflang points seulement at live,
canonical, indexable URLs — regenerated whenever URLs modifier.
5. Relative or protocol-relative URLs.
Pourquoi it’s incorrect: Google exige fully-qualified URLs; /foo and //example.com/foo
are invalid, and même absolute-but-mismatched formulaires (incorrect slash/www/cas) échouer the
reciprocity match.
Do à la place: toujours https://example.com/foo, matching the exact indexé formulaire.
6. Trusting “View Page Source” as validation.
Pourquoi it’s incorrect: JS-injected hreflang doesn’t apparaître in raw source, so vous soit
think it’s manquant (it isn’t) or miss que it renders in the <body> (invalid).
Do à la place: validate the rendered DOM via GSC Inspection d’URL or a rendering
robot d’exploration.
7. Incorrect or invented locale codes.
Pourquoi it’s incorrect: en-UK, jp, ger, and region-only codes are invalid and
ignored.
Do à la place: ISO 639-1 language + optional ISO 3166-1 alpha-2 region — en-GB,
ja, de, es-MX.
Avant / après
1. Manquant reciprocal tag (the classic). Avant: the US page listes US + UK + DE, but the German page’s template seulement listes DE + US — it forgot the UK retourner lien. Google drops the DE↔UK pair. Après: the German page’s block listes DE + US + UK (tout self-referencing and reciprocal). Regenerated from the locale table so it can’t drift à nouveau.
2. Relative URLs.
Avant: <link rel="alternate" hreflang="de" href="/de/" /> — relative, so it’s
invalid and ignored.
Après: <link rel="alternate" hreflang="de" href="https://example.com/de/" /> —
fully-qualified and matching the indexé formulaire.
3. Incorrect UK code.
Avant: <link rel="alternate" hreflang="en-uk" href="https://example.com/uk/" />
— uk is Ukrainian; the annotation is invalid.
Après: <link rel="alternate" hreflang="en-gb" href="https://example.com/uk/" />.
4. Sitemap manquant the namespace.
Avant: a sitemap en utilisant <xhtml:link> entries but with a <urlset> que seulement
declares the base sitemaps namespace — every <xhtml:link> is invalid.
Après: <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, alors paste into votre assistant of choice. Toujours validate the output contre a réel explorer — an LLM peut generate plausible-but-wrong codes or miss a retourner lien.
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 même matrix into an XML sitemap 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 pour 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 pour building and checking hreflang. Adjust URLs avant running.
Chrome DevTools Console — liste the hreflang tags on the current page Paste into the Console (F12 → Console) on quelconque page to voir ce que le navigateur en réalité rendered — ce reflects JS-injected tags que “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 pour the <head>-break bug: quelconque tag showing
inHead: false is rendering in the <body> and is invalid.
Bookmarklet — même vérifier, un click Enregistrer as a bookmark with ce URL, alors click it on quelconque 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 liens à l’intérieur the head (pour a robot d’exploration / navigateur inspector)
//head/link[@rel='alternate' and @hreflang]Si a robot d’exploration trouve link[@hreflang] matches sous //body à la place, that’s the
head-break bug.
Regex — pull hreflang code + URL from raw HTML (rapide grep, pas a réel parser)
<link[^>]*rel=["']alternate["'][^>]*hreflang=["']([^"']+)["'][^>]*href=["']([^"']+)["']Capture groupe 1 is le code, groupe 2 is l’URL. Utiliser seulement pour a fast sanity grep — parse réel HTML with a DOM library, pas regex.
curl — vérifier pour hreflang in HTTP Link: réponse headers (the PDF/non-HTML cas)
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) Testez vos connaissances: Implementing hreflang
Five rapide questions on building a hreflang cluster correctement. Pick an réponse pour chaque, alors vérifier.
Ressources utiles
My connexe writing
- Hreflang: The Facile Guide pour Beginners — my Ahrefs guide with tout three méthodes, the nine courant implementation problèmes and fixes, and the Google Sheets template pour semi-automated hreflang generation at scale.
- Over 67% of Domains En utilisant Hreflang Have Problèmes — my study of 374 756 domains, the largest ever run, and the source of the error-rate breakdown (manquant x-default 56,3%, manquant self-reference 18,0%, broken/redirigé targets 16,9%, manquant 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 iframes/malformed markup) and DOM-breakpoint debugging, pourquoi “sitemaps are faster” is a myth, the geo-redirect de-indexing risk, and the&hl=/&gl=SERP-check technique. - Hreflang Study and Interesting Problèmes — Brighton SEO 2023 — the deck behind the study, plus Google’s most-specific matching order (language+country → language → x-default) and the la plupart courant code mistakes à travers the dataset.
- You’re Going To Screw Up International SEO — Pubcon Vegas 2017 — the ecosystem of implementation chaos: outils reporting incorrect info, content served from URLs que differ from what’s indexé, duplicate-page traps.
From autour the industry
- Google’s Localized versions of votre pages — the principal implementation doc; the exact syntax pour tout three méthodes, the reciprocity/self-reference rules, valid codes, and the absolute-URL requirement. Lire it in complet avant vous construire.
- Google’s Managing multi-regional and multilingual sites — URL-structure options and the auto-redirect / cloaking warning behind “redirect users, not crawlers.”
- WPML — En utilisant WordPress SEO (Yoast) with WPML — how WordPress en réalité outputs hreflang (Yoast alone doesn’t), and the head-vs-sitemap output setting.
- Shopify — Ajouter hreflang tags in votre theme — the manual
theme.liquid<link>pattern pour quand Shopify Markets’ language-only tags aren’t spécifique suffisant. - Screaming Frog — How To Audit & Tester Hreflang — the crawl-based workflow pour confirming reciprocity à travers a whole cluster plutôt que spot-checking un URL.
- Google Reminds Que Hreflang Tags Are Hints, Pas Directives — Moteur de recherche Journal, May 2025, on Mueller’s same-language-consolidation clarification (pourquoi a technically perfect cluster peut encore be consolidated).
- r/TechSEO — the community pour debugging broken hreflang clusters.
Prove the hreflang cluster en réalité shipped
Hreflang fails silently: the tags peut be présent, well-formed, and encore ignored si the retourner leg is manquant. “It’s in the code” n’est pas the tester — reciprocity à travers the whole cluster is. Run ces après vous deploy a language/region définir.
Tester 1 — Every pair renvoie the tag (reciprocity)
- Tester to run — Explorer the whole cluster with returntag (it checks que every page A points to en réalité points back at A), or run Screaming Frog’s hreflang report à travers the définir.
- Attendu result — 0 non-reciprocal pairs and every URL self-references. Zero errors, pas “a few.”
- Échec interpretation — A one-way pair (A → B but B doesn’t → A) signifie Google drops que pair — the la plupart courant real-world échec, and invisible si vous seulement spot-check un URL’s view-source.
- Monitoring window — Immediate pour the rendered tags; the checker reads what’s live now.
- Rollback trigger — Quelconque non-reciprocal pair, or a tag pointing at une URL que 301s or 404s — fix the source of truth and redeploy avant waiting on Google.
Tester 2 — Google is processing it cleanly
- Tester to run — Google retired the old International Targeting report in Search Console in September 2022, so don’t rely on it — vérifier Page Indexation pour chaque locale in the cluster, and confirmer via Inspection d’URL on a sample of pages que the “Google-selected canonical” and indexation status line up with ce que vous expect pour que locale.
- Attendu result — Chaque locale’s intended pages are indexé (pas “Duplicate, Google chose different canonical” in a façon que collapses distinct language versions into un), and Inspection d’URL montre the alternate vous expect.
- Échec interpretation — Pages showing up as duplicates of a différent locale’s canonical, or clustered/consolidated indexation, usually traces back to a broken retourner leg (re-check Tester 1) plutôt que hreflang itself — hreflang is a hint, pas a directive, so a technically perfect cluster peut encore be consolidated si Google judges le contenu near-duplicate.
- Monitoring window — 2–4 weeks — Search Console re-crawls and reports the cluster over temps, pas instantly.
- Rollback trigger — A locale’s pages consistently indexation sous the incorrect canonical, or the incorrect regional URL surfacing pour a requête — re-audit reciprocity premier; don’t assume the tags “aren’t working” quand the retourner leg is the réel gap.
Journal des modifications
Mis à jour le 25 juil. 2026.
Résumé éditorial et détails enregistrés des changements.Détails des changements
-
Les notes détaillées des changements sont actuellement disponibles en anglais.
Comparaison complète indisponible — aucun instantané antérieur n’a été archivé pour cette révision.
Mis à jour le 18 juil. 2026.
Résumé éditorial et détails enregistrés des changements.Détails des changements
-
Les notes détaillées des changements sont actuellement disponibles en anglais.
-
Les notes détaillées des changements sont actuellement disponibles en anglais.
-
Les notes détaillées des changements sont actuellement disponibles en anglais.
-
Les notes détaillées des changements sont actuellement disponibles en anglais.
Comparaison complète indisponible — aucun instantané antérieur n’a été archivé pour cette révision.