Hreflang alternate links: reciprocal clusters, x-default, and BCP 47 codes
Published: 2026-09-05
How hreflang alternate links tell search engines which language or region URL to show, why every page must list the full reciprocal cluster, when to use x-default, and how BCP 47 codes are written.
hreflang tells search engines that several URLs are language or region variants of the same content. When someone searches in Spanish, Google can prefer your /es/ page instead of the English one—if the alternate set is complete, consistent, and reciprocal. Incomplete clusters are one of the most common multilingual SEO mistakes: a page that only links “out” to other locales, without those locales linking back with the same set, is often ignored.
This guide covers <link rel="alternate" hreflang>, reciprocal clusters, x-default, and BCP 47–style codes. Draft the matrix locally so staging hosts and unreleased locale paths never need to leave your machine—see Why “local only” matters for developer tools. Hreflang sits beside meta / Open Graph tags, robots.txt, and sitemaps: each layer does a different job.
What hreflang actually declares
Each alternate is a pair: a language (and optional region/script) code plus an absolute URL of that version. In HTML you emit one tag per variant (including a self-reference to the current page’s URL):
<link rel="alternate" hreflang="en" href="https://example.com/en/">
<link rel="alternate" hreflang="es" href="https://example.com/es/">
<link rel="alternate" hreflang="fr" href="https://example.com/fr/">
<link rel="alternate" hreflang="x-default" href="https://example.com/">
| Piece | Role |
|---|---|
rel="alternate" |
Marks another representation of this content |
hreflang |
Language / region (or x-default) for that URL |
href |
Absolute URL of that language version |
You can also send the same relationships as an HTTP Link header (RFC 8288). Prefer one delivery method per site so you do not maintain two diverging sources of truth. HTML <head> tags are the usual choice for static and CMS sites; headers help when HTML is hard to change but the edge/CDN can inject Link.
Hreflang does not replace a canonical URL. Canonical says “this is the preferred URL for this document.” Hreflang says “these other documents are translations / region variants.” Use both when you have true language versions—not when you merely have query-param duplicates of one page.
Reciprocal clusters (the rule that breaks most setups)
Google expects a closed cluster: every URL in the set should list the same full set of alternates, including itself. If /en/ points at /es/ and /fr/, then /es/ and /fr/ must also point at /en/, /es/, and /fr/ (plus x-default if you use it).
| Bad pattern | Why it fails |
|---|---|
| Only the homepage lists alternates | Locale subpages never declare the cluster |
| EN → ES, but ES has no hreflang | One-way links; cluster incomplete |
EN lists en + es; ES lists only es |
Missing return and self links |
Different URLs for the same hreflang on different pages |
Conflicting signals for that language |
Practical habits:
- Build the locale ↔ URL matrix once for a content template (product page, blog post, docs path).
- Paste the same snippet into every localized template (or generate it from one source of truth in your CMS).
- After deploy, spot-check View Source on two locales and confirm the
hrefsets match.
Tools that only generate tags for “this page” without reminding you to deploy the full set encourage half-clusters. Treat the output as a cluster definition, not a one-off for the English page.
x-default: the unmatched-language fallback
x-default is not a language. It points to the URL you want when the user’s language does not match any listed hreflang—often a language chooser, a geo-agnostic homepage, or your primary marketing URL.
<link rel="alternate" hreflang="x-default" href="https://example.com/">
| Situation | Sensible x-default |
|---|---|
Path locales (/en/, /de/, …) |
Site root or a language picker |
Country sites (example.de, example.fr) |
Global brand domain |
| Single default language for everyone else | Your primary locale URL (can equal the en URL) |
You only need one x-default per cluster. If a matrix row already uses x-default, do not also emit a second one from a separate field. With two or more language rows and no x-default, engines still process the cluster—but users without a matching language get weaker guidance, so many sites add it once they have a clear fallback URL.
BCP 47–style codes Google expects
Search engines expect simplified BCP 47 tags: language, optional script, optional region—not free-form labels like english or EN_US.
| Form | Example | Meaning |
|---|---|---|
| Language only | en, de, ja |
Content for that language, any region |
| Language + region | en-US, en-GB, pt-BR |
Language tailored to a region |
| Language + script | zh-Hans, zh-Hant |
Simplified vs traditional Chinese script |
| Fallback | x-default |
Unmatched languages |
Casing conventions (language lower, region upper, script title-case) help humans and validators; many generators normalize en-us → en-US for you. Underscores (en_US) belong in Open Graph og:locale, not in hreflang.
Choose language-only when one URL serves all English speakers. Use language-region when US and UK pages truly differ (spelling, currency, legal copy). Do not invent pairs like en and en-US for the same URL—pick one code per URL, and do not duplicate the same code on two different URLs in one cluster.
Absolute URLs, self-references, and sitemap siblings
- Prefer
https://absolutehrefvalues. Relative paths andlocalhostare easy to ship by mistake and hard for crawlers to resolve across hosts. - Include a self-referencing alternate: the page’s own URL appears with its own
hreflang. - Keep slug and path rules stable so locale URLs do not churn after you publish the cluster.
- List the same URLs in your sitemap when appropriate; sitemaps can also carry hreflang annotations, but HTML/header and sitemap signals should agree.
Hreflang will not fix thin auto-translated pages or doorway country clones. Engines still evaluate content quality; alternates only map which URL fits which language intent.
A safe local drafting workflow
- List every real language/region version and its production absolute URL (path prefixes, subdomains, or ccTLDs).
- Add
x-defaultif you have a clear unmatched-language destination. - Optionally fill URLs from a pattern such as
https://example.com/{lang}/pageso path codes stay consistent. - Generate HTML
<link>tags (or an HTTPLinkheader) and paste the same reciprocal set into every locale’s<head>. - After deploy, use Google Search Console international / hreflang reports (or equivalent) to catch missing return links—generators do not crawl your live site.
Building the matrix in-tab keeps draft locale maps and unreleased hosts on your device. For the privacy model, see Why “local only” matters for developer tools.
Try it locally in your browser
Use the hreflang tags generator to:
- Start from presets (EN/ES/FR, EN-US/EN-GB/ES, or path locales) or build a custom locale matrix.
- Set an optional x-default URL and apply a
{lang}/{LANG}URL pattern to fill rows in bulk. - Copy paste-ready HTML
<link>tags or an HTTP Link header—generation runs only in this tab; nothing is uploaded to LocalTools.
Watch the in-tool checks for invalid codes, duplicate hreflang values, and non-absolute URLs before you ship the cluster to every locale template.
Related reading
- Open Graph and Twitter Card meta tags: what to put in
<head>— share and basic SEO tags that sit next to hreflang in<head>. - Writing robots.txt: User-agent groups, Allow/Disallow, and Sitemap tips — crawl rules for localized paths.
- Auditing sitemap.xml: urlset vs index, URL counts, and duplicate loc checks — advertising every locale URL consistently.
- Slug rules for URLs and filenames — stable public paths for each language version.
- Why “local only” matters for developer tools — why draft SEO matrices belong in-tab, not on a random paste site.