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:

  1. Build the locale ↔ URL matrix once for a content template (product page, blog post, docs path).
  2. Paste the same snippet into every localized template (or generate it from one source of truth in your CMS).
  3. After deploy, spot-check View Source on two locales and confirm the href sets 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-usen-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:// absolute href values. Relative paths and localhost are 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

  1. List every real language/region version and its production absolute URL (path prefixes, subdomains, or ccTLDs).
  2. Add x-default if you have a clear unmatched-language destination.
  3. Optionally fill URLs from a pattern such as https://example.com/{lang}/page so path codes stay consistent.
  4. Generate HTML <link> tags (or an HTTP Link header) and paste the same reciprocal set into every locale’s <head>.
  5. 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

All learn articles