Hreflang tags: a complete guide with examples
·4 min read
Hreflang is an annotation that tells Google which URLs are language or regional versions of the same page, so a searcher in Mexico gets your Spanish page and a searcher in London gets the en-GB one. You declare hreflang tags in the HTML head, in an HTTP header or in your XML sitemap. Every version must list itself and every other version, and each listed page must link back, or Google ignores the pair.
That last rule is where most sites break. The syntax is easy. Keeping fifteen pages in agreement is not.
What hreflang tags do
Hreflang tags tell Search which URL to show for a given language or region. Google's localized versions guide says the annotations help it point users to the most appropriate version, and the choice depends on the user's language settings.
Three things hreflang does not do:
- It does not tell Google what language a page is in. Google detects that with its own algorithms and ignores both hreflang and the HTML
langattribute for that job. - It does not redirect anyone. It only changes which URL appears in the results.
- It does not make translated pages count as duplicates. Per the same guide, localized versions are duplicates only when the main content stays untranslated.
Use it when you have the same page in several languages, or the same language for several countries with different prices, spelling or shipping. A site in one language for one market needs none of it.
Three ways to add hreflang tags
Google treats the HTML, HTTP header and sitemap methods as equivalent. Pick one per page. Using two adds nothing and doubles the places the sets can drift apart.
HTML link elements
Put one <link> per version inside the <head>. The block is identical on every version, including the page's own entry.
<head>
<link rel="alternate" hreflang="en" href="https://example.com/en/pricing" />
<link rel="alternate" hreflang="en-GB" href="https://example.com/uk/pricing" />
<link rel="alternate" hreflang="es-MX" href="https://example.com/mx/pricing" />
<link rel="alternate" hreflang="x-default" href="https://example.com/pricing" />
</head>The tags must sit in a well-formed head, so check that nothing invalid above them closes the head early.
HTTP Link header
For PDFs and other non-HTML files, send the set in a Link header on the GET response.
Link: <https://example.com/en/guide.pdf>; rel="alternate"; hreflang="en",
<https://example.com/de/guide.pdf>; rel="alternate"; hreflang="de"XML sitemap
Each <url> lists its own <loc> plus an xhtml:link for every version, itself included. The xhtml namespace is required.
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://example.com/en/pricing</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/pricing"/>
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/pricing"/>
</url>
<url>
<loc>https://example.com/de/pricing</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/pricing"/>
<xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/pricing"/>
</url>
</urlset>I prefer the sitemap on large sites because one generated file is easier to keep consistent than tags spread across templates. Our XML sitemap guide covers the rest of the format.
In all three methods, URLs must be fully qualified with the protocol. /de/pricing and //example.com/de/pricing are both invalid. Alternates may live on other domains.
Hreflang language and region codes
The value is an ISO 639-1 language code, optionally followed by an ISO 3166-1 Alpha 2 region code. Codes are case-insensitive, so en-gb works, though en-GB is the usual style.
| Value | Meaning |
|---|---|
de |
German, any region |
de-AT |
German speakers in Austria |
zh-Hant |
Chinese in Traditional script (ISO 15924 script code) |
en-GB |
English speakers in the United Kingdom |
x-default |
Fallback for everyone else |
The mistakes I see most:
- Region on its own.
beis Belarusian, not Belgium. A region always needs a language in front of it. - Country codes used as languages.
jpshould beja,cnshould bezh-CN,dkshould beda. en-UK. Google ignores reserved codes such as UK and EU. Useen-GB.es-419. Google does not support numeric region codes. Point each Latin American market at its own code or use plaines.en_US. That is a locale string from your CMS, not a valid value. Use a hyphen.
Return links and self-reference
Every page in a set must list itself and every other version, and each listed page must list it back. If page A names page B and B does not name A, Google ignores the annotation. Google's guide says this stops other sites from claiming your pages as their alternates.
Self-reference feels redundant, but it is required. The English page lists the English URL along with the German and Spanish ones.
When a full set is hard to maintain, Google allows partial sets. Link each new version both ways with your main language version first, then fill in the rest.
The fallback for unmatched languages is x-default, usually your language selector or home page. The details are in hreflang x-default.
Hreflang and canonical tags
Each language version should be canonical to itself. Google's duplicate URL guide says to specify a canonical page in the same language, or the best substitute language.
The classic break is a German page with rel="canonical" pointing at the English page. That tells Google the German page is a duplicate, so it folds into the English URL and the hreflang pointing at it has nothing to land on. Also list only the canonical URL in your hreflang set. A URL that redirects or carries tracking parameters will not match the return link. Our canonical tag guide covers self-referencing canonicals in more depth.
Google also ignores canonical tags that carry an hreflang attribute, so do not try to combine the two in one element.
Check your hreflang tags
The Hreflang Checker reads the hreflang tags in a page's HTML head and its HTTP Link header. It flags invalid codes with the value Google expects, duplicate codes, relative URLs, a missing self-reference, a missing x-default, an html lang that disagrees with the page's own code, and a canonical pointing elsewhere. It then fetches up to 20 listed versions and reports whether each loads, redirects, is noindex, is canonicalized away, or fails to link back.
A run costs 10 credits per page. It does not read hreflang in XML sitemaps and does not crawl the whole site, so run it once on each page template you use.