Blog

Hreflang tags: a complete guide with examples

Hreflang tells Google that several pages are the same content for different languages or countries, so it can show a German speaker the German page and a British shopper the UK page. It's simple in principle and easy to get subtly wrong, and when it's wrong, Google quietly ignores it.

What hreflang does, and doesn't

Hreflang is an attribute on a link that says "this other URL is the version of this page for language X, optionally in country Y". Google uses it to pick which version to show in its results for each searcher.

It helps when you have:

What it doesn't do: it doesn't raise rankings, it doesn't translate anything, and it isn't how Google works out a page's language. Google's documentation says it detects language with its own algorithms and doesn't use hreflang or the HTML lang attribute for that. Hreflang only connects versions that already exist.

It also doesn't make translated pages count as duplicates. Google treats localised versions as duplicates only when the main content is left untranslated.

How a hreflang cluster works

All versions of a page form a cluster, and two rules hold the cluster together:

  1. Every version lists every version, including itself. The English page lists English, German and French; so do the German and French pages.
  2. Every link must be returned. If the English page points to the German page, the German page must point back to the English page with exactly the same URL. Google says that if two pages don't both point to each other, the tags are ignored.

The return-link rule stops anyone from declaring themselves the "German version" of your site. In practice it means the simplest correct setup is one identical block of tags on every page of the cluster:

<link rel="alternate" hreflang="en" href="https://example.com/shoes/">
<link rel="alternate" hreflang="de" href="https://example.com/de/schuhe/">
<link rel="alternate" hreflang="fr" href="https://example.com/fr/chaussures/">
<link rel="alternate" hreflang="x-default" href="https://example.com/shoes/">

Pairs are judged one at a time. If the French page forgets to link to the German one, only that pair is ignored; English–German and English–French still work.

Language and country codes

A hreflang value is a language code from ISO 639-1, optionally followed by a hyphen and a country code from ISO 3166-1 alpha-2. A script code from ISO 15924 can sit between them for languages written in more than one script. Case doesn't matter, though countries are usually written in capitals.

CodeValid?Meaning or fix
deYesGerman, for German speakers everywhere
de-ATYesGerman for Austria
zh-HantYesChinese in Traditional script
en-UKNoThe UK's code is GB: use en-GB
en_USNoUnderscores aren't allowed: use en-US
gb, usNoA country can't be used alone; the language always comes first
jp, cn, dkNoThese are countries. The languages are ja, zh and da
es-419NoGoogle doesn't support UN region numbers. Use es, or list each country
en-EUNoEU isn't a country code. Google says reserved codes such as EU, UN and UK have no effect

Use a country only when that country gets a genuinely different page. If one Spanish page serves every Spanish speaker, es is right and es-ES, es-MX and so on add nothing. When you do split by country, Google recommends also giving one version the language alone, so speakers in countries you didn't list still get a match.

x-default

hreflang="x-default" names the page for everyone who matches none of your versions. It's usually one of two things:

x-default is optional, but it's the cleanest way to say what happens to a Brazilian visitor on a site with only English, German and French versions. Like every other entry, it belongs in the block on every page of the cluster.

Three ways to add hreflang

Google treats the three methods as equivalent. Pick one per set of pages; using two or three gives no extra benefit and makes them harder to keep in step.

1. Link tags in the HTML head

The block shown above, inside the page's <head>. This is the most common method and the easiest to check. The tags must be in a well-formed head: an element that doesn't belong there, such as an <img> or a <div> injected by a script, ends the head early, and any hreflang tags after it are lost.

2. The HTTP Link header

For files with no HTML head, such as PDFs, the same information goes in a response header:

Link: <https://example.com/guide.pdf>; rel="alternate"; hreflang="en",
      <https://example.com/de/leitfaden.pdf>; rel="alternate"; hreflang="de"

3. The XML sitemap

On large sites, adding tags to every page template can be heavy. Instead, each URL in the sitemap lists its alternates, using the xhtml namespace:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <url>
    <loc>https://example.com/shoes/</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://example.com/shoes/"/>
    <xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/schuhe/"/>
  </url>
  <url>
    <loc>https://example.com/de/schuhe/</loc>
    <xhtml:link rel="alternate" hreflang="en" href="https://example.com/shoes/"/>
    <xhtml:link rel="alternate" hreflang="de" href="https://example.com/de/schuhe/"/>
  </url>
</urlset>

Every version still needs its own <url> entry with the full set, including itself. The downside is visibility: nobody notices broken sitemap hreflang by looking at a page.

Hreflang with canonicals, redirects and noindex

Hreflang should only ever point to URLs Google can index and treats as canonical:

WordPress, Shopify and other platforms

Whatever the platform, check the output, not the settings screen.

Common mistakes

  1. Missing return links, usually because one version was added or moved later.
  2. Invalid codes, especially en-UK, underscores and country codes used as languages.
  3. Pointing at URLs that redirect, often the http:// or non-www form.
  4. Canonical tags that point every version to one language.
  5. Relative URLs such as /de/ instead of full URLs.
  6. Two different URLs given the same code.
  7. Tags placed in the <body>, or after something that ends the head early.

How to test it

Because hreflang only works when pages agree with each other, checking one page isn't enough; every version has to be fetched and compared. A hreflang checker does that from a single URL: it validates each code, fetches every alternate, and shows a matrix of which page links back to which:

Run it on one page of each template, such as the homepage, a category page and a product or article page, since hreflang is usually generated per template. Search Console no longer has an international targeting report (Google retired it in 2022), so a checker is now the main way to catch errors.

Questions

What does hreflang mean?

It's the "language of the linked page" attribute (href + lang): it marks a linked URL as the version of a page for a particular language, and optionally a particular country.

What is hreflang x-default?

A special value for the page to show visitors whose language or country matches none of your versions, usually a language selector or your main international page.

Do I need hreflang if my site is in one language?

No. Hreflang is only for sites with more than one language or regional version of the same pages.

Is hreflang a directive?

Treat it as a strong signal rather than a command. Google uses it to choose between versions, but may still show a different version if the annotations are broken or the pages disagree.

Should I use hreflang or the lang attribute?

Both, for different jobs. <html lang> declares the language of the page for browsers, screen readers and translation tools; hreflang links the versions together for search engines.