hreflang for Multilingual Sites

Serve the right language or region version with hreflang annotations.

hreflang tags tell search engines which language and region each version of a page targets, so users see the correct one.

Rules

  • Use ISO language codes, optionally with a region (en, en-GB, es-MX).
  • Annotations must be reciprocal - every version links to all the others, including itself.
  • Add an x-default for a fallback version.

Where to place them

You can add hreflang in the HTML head, in HTTP headers, or in the XML sitemap. Pick one method and be consistent.

Example

Example · html
<link rel="alternate" hreflang="en" href="https://example.com/guide">
<link rel="alternate" hreflang="es" href="https://example.com/es/guia">
<link rel="alternate" hreflang="x-default" href="https://example.com/guide">

When to use it

  • A travel booking site uses hreflang to serve French speakers in France the /fr/ version and French-Canadian speakers the /fr-ca/ version of each page.
  • An international e-commerce store uses hreflang x-default to designate its English homepage as the fallback for unsupported locales.
  • A global news publisher audits hreflang annotations after noticing the German audience is landing on the English site, revealing missing return tags.

More examples

hreflang annotation in HTML head

Each hreflang annotation must be present on every alternate page and must form a complete, reciprocal set to be recognised by Google.

Example · html
<head>
  <!-- English (UK) — current page -->
  <link rel="alternate" hreflang="en-gb" href="https://example.com/en-gb/shoes/">
  <!-- French (France) -->
  <link rel="alternate" hreflang="fr-fr" href="https://example.com/fr-fr/chaussures/">
  <!-- French (Canada) -->
  <link rel="alternate" hreflang="fr-ca" href="https://example.com/fr-ca/chaussures/">
  <!-- Fallback for all other locales -->
  <link rel="alternate" hreflang="x-default" href="https://example.com/shoes/">
</head>

hreflang via XML sitemap

Declaring hreflang in the sitemap is the recommended approach for large sites where editing every page's head is impractical.

Example · bash
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <url>
    <loc>https://example.com/en-gb/shoes/</loc>
    <xhtml:link rel="alternate" hreflang="en-gb" href="https://example.com/en-gb/shoes/"/>
    <xhtml:link rel="alternate" hreflang="fr-fr" href="https://example.com/fr-fr/chaussures/"/>
    <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/shoes/"/>
  </url>
</urlset>

Validate hreflang reciprocal links

Fetching hreflang tags from each alternate URL and comparing them validates that all pages declare reciprocal annotations, preventing orphaned locale signals.

Example · bash
python3 - << 'EOF'
import requests
from bs4 import BeautifulSoup

def get_hreflang(url):
    soup = BeautifulSoup(requests.get(url, timeout=5).text, 'html.parser')
    return {t.get('hreflang'): t.get('href')
            for t in soup.find_all('link', rel='alternate') if t.get('hreflang')}

urls = [
    "https://example.com/en-gb/shoes/",
    "https://example.com/fr-fr/chaussures/",
]
results = {u: get_hreflang(u) for u in urls}
for url, tags in results.items():
    print(f"\n{url}")
    for lang, href in tags.items():
        print(f"  hreflang={lang}: {href}")
EOF

Discussion

  • Be the first to comment on this lesson.