OctaneAudit
Technical SEO

10 Common Hreflang Mistakes and How to Fix Each One

Hreflang fails silently. These are the ten hreflang mistakes that most often break international targeting, with the fix and a code sample for each.

OCOctaneAudit Team9 min read
Technical SEO

10 Common Hreflang Mistakes and How to Fix Each One

Hreflang tells Google which language or regional version of a page to show to which searcher. When it works, a user in Germany sees your German page and a user in Australia sees your Australian English page. When it breaks, Google quietly ignores the annotations, and you find out months later when the wrong country version ranks.

There is no error banner for this. Search Console's International Targeting report was retired in 2022, so you have to find hreflang mistakes yourself, with a crawler and some careful reading of the source.

How hreflang is supposed to work

Every page in a set of alternates lists every version, including itself, plus an optional x-default fallback. A minimal correct cluster for three versions looks like this, and the same block appears on all three pages:

<link rel="alternate" hreflang="en-us" href="https://www.example.com/us/pricing/">
<link rel="alternate" hreflang="en-gb" href="https://www.example.com/uk/pricing/">
<link rel="alternate" hreflang="de-de" href="https://www.example.com/de/preise/">
<link rel="alternate" hreflang="x-default" href="https://www.example.com/pricing/">

You can deliver the same information in three ways: link elements in the HTML head, Link HTTP headers (useful for PDFs and other non-HTML files), or xhtml:link entries in an XML sitemap. Google treats them as equivalent.

Keep that model in mind. Almost every mistake below is a way of breaking it.

Hreflang must be reciprocal. If the US page points to the UK page, the UK page must point back to the US page. When the return link is missing, Google ignores that pair.

This usually happens when one regional team updates its templates and another does not, or when a new locale launches and only its own pages get the full set.

Fix: generate the hreflang block for a page from one shared source of truth (a locale mapping table in your CMS or database), not from per-locale templates. Then crawl every locale and check that each annotation has a matching return.

2. Invalid language or region codes

Hreflang values use an ISO 639-1 language code, optionally followed by an ISO 3166-1 alpha-2 region code. Values are not case sensitive, but they must be valid.

WrongWhy it failsCorrect
en-ukUK is not an ISO 3166-1 country code; the United Kingdom is GBen-gb
gbA region alone is not allowed; language is requireden-gb
en-euEU is not a country codeOne tag per country, or plain en
es-laLA is the country code for Laos, not Latin Americaes, or specific countries such as es-mx and es-ar
jpThe language code for Japanese is jaja or ja-jp
en_USUnderscore instead of hyphenen-us
zh-cn used for Traditional ChineseScript mismatchzh-hant or zh-tw for Traditional, zh-hans or zh-cn for Simplified

Fix: validate every value against the ISO lists in your build or a crawler check. A typo in a template propagates to every page.

3. No self-referencing annotation

Each page should include itself in its own hreflang set. Leaving the current page out is one of the most common hreflang mistakes on sites that build the block by looping over "other" locales.

<link rel="alternate" hreflang="de-de" href="https://www.example.com/de/preise/">
<link rel="alternate" hreflang="en-us" href="https://www.example.com/us/pricing/">
<link rel="alternate" hreflang="en-gb" href="https://www.example.com/uk/pricing/">

On the German page, that first line is the self-reference. It belongs on the page alongside the others.

Fix: loop over all locales, including the current one.

4. Relative or inconsistent URLs

Hreflang URLs must be fully qualified, including protocol and hostname. /de/preise/ is not valid. Equally harmful is pointing at the right path on the wrong variant: http:// instead of https://, or example.com instead of www.example.com. Those URLs redirect, which leads directly to mistake number 5.

Fix: build hreflang URLs from the same canonical base URL setting your canonical tags use.

5. Pointing at URLs that redirect, error or are noindexed

Every URL in a hreflang set should return 200, be indexable, and be the canonical version of that page. Common failures:

  • A locale's page was moved and now 301 redirects.
  • A locale never got a translation and returns 404.
  • A staging locale is live with a noindex tag but still referenced from production pages.
  • The URL is blocked in robots.txt, so Google cannot crawl it to confirm the return link. See robots.txt vs noindex vs nofollow for why blocked pages cannot pass their signals.

Fix: only output an alternate when the target page exists, returns 200 and is indexable. If a page has no German translation, leave German out of that page's set rather than pointing at the German homepage.

6. Conflicts with canonical tags

Hreflang and canonical tags must agree. The classic mistake is canonicalizing every regional version to one "main" version:

<link rel="canonical" href="https://www.example.com/us/pricing/">
<link rel="alternate" hreflang="en-gb" href="https://www.example.com/uk/pricing/">

If that appears on the UK page, it tells Google the UK page is a duplicate of the US page and should not be indexed, while hreflang says it is the UK version. Google will usually honor the canonical and drop the UK page.

Fix: each locale page should have a self-referencing canonical, and hreflang should point only at canonical URLs. Our canonical tags guide covers how the two signals interact in more detail.

7. Missing or misused x-default

x-default is the page to show when no other version matches the user's language or region. It is typically a language selector or your global version. It is optional, but without it, a searcher in an unlisted country gets whichever version Google picks.

The misuse is pointing x-default at different URLs from different pages in the same cluster, or at a URL that redirects based on IP.

Fix: pick one x-default per cluster and use it consistently on every page in that cluster.

8. Annotations outside the head, or a broken head

Hreflang link elements are only read in the head. Two ways they end up elsewhere:

  • The theme or tag manager outputs them in the body.
  • An element that is not allowed in the head, such as an img, an iframe or a stray text node, appears before them. Parsers close the head at that point, and everything after it is treated as body content.

The second one is easy to miss, because the source code looks correct. A tracking pixel injected high in the head can silently move your hreflang, canonical and meta robots tags into the body.

Fix: view the rendered DOM (DevTools Elements panel or the URL Inspection tool's rendered HTML), not just the raw source, and confirm the link elements sit inside head. Put hreflang and canonical tags as early in the head as possible. If annotations are injected with JavaScript, make sure they are present in the rendered HTML; server-rendered output is far more reliable. Our guide to JavaScript SEO and rendering explains why.

9. Automatic redirects by IP or browser language

Redirecting users to a locale based on IP address or the Accept-Language header seems helpful, but it fights hreflang. Googlebot mostly crawls from US IP addresses and usually does not send an Accept-Language header, so if your site redirects by location, Google may never see your non-US pages at all.

Fix: do not force-redirect. Serve the requested URL, and show a dismissible banner suggesting the user's likely locale. If you must redirect the root URL, make it the x-default and keep every locale URL directly reachable.

10. Inconsistent or incomplete sets across methods

Large sites often move hreflang into XML sitemaps to keep HTML lighter. Problems appear when:

  • Both HTML and sitemap annotations exist and disagree after a migration.
  • A sitemap lists only some URLs in a cluster, so return links are missing.
  • Sitemaps are split by locale without each entry listing the full set.

A correct sitemap entry lists every alternate, including itself, and the same set repeats under each URL in the cluster:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <url>
    <loc>https://www.example.com/us/pricing/</loc>
    <xhtml:link rel="alternate" hreflang="en-us" href="https://www.example.com/us/pricing/"/>
    <xhtml:link rel="alternate" hreflang="en-gb" href="https://www.example.com/uk/pricing/"/>
    <xhtml:link rel="alternate" hreflang="de-de" href="https://www.example.com/de/preise/"/>
    <xhtml:link rel="alternate" hreflang="x-default" href="https://www.example.com/pricing/"/>
  </url>
  <url>
    <loc>https://www.example.com/uk/pricing/</loc>
    <xhtml:link rel="alternate" hreflang="en-us" href="https://www.example.com/us/pricing/"/>
    <xhtml:link rel="alternate" hreflang="en-gb" href="https://www.example.com/uk/pricing/"/>
    <xhtml:link rel="alternate" hreflang="de-de" href="https://www.example.com/de/preise/"/>
    <xhtml:link rel="alternate" hreflang="x-default" href="https://www.example.com/pricing/"/>
  </url>
</urlset>

For PDFs and other files, the HTTP header form looks like this:

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

Fix: choose one primary method per content type and remove the others. Generate sitemap clusters from the same locale mapping that drives the site.

How to audit hreflang

A repeatable process:

  1. Crawl every locale with a crawler that extracts hreflang (Screaming Frog, Sitebulb or similar). Start from each locale's homepage, not just the main one.
  2. Report on reciprocity. List annotations with no return link. This catches mistakes 1 and 3.
  3. Validate codes against ISO 639-1 and ISO 3166-1 alpha-2.
  4. Check targets. Every hreflang URL should return 200, be indexable, and be self-canonical. This catches mistakes 4, 5 and 6.
  5. Inspect rendered HTML for a sample of templates to confirm annotations are in the head.
  6. Test from other locations. Request locale URLs with a US IP and no Accept-Language header and confirm there are no redirects.
  7. Spot check results. In Search Console, filter Performance by country and check which URLs get impressions. If the US page gets most UK impressions, the cluster is not being honored.

Hreflang is a signal, not a directive. Even a perfect implementation does not guarantee Google shows the expected version every time, but a broken one guarantees it will not. Because a single template change can break every cluster at once, it is worth tracking continuously. AI Monitoring checks status codes, canonicals and indexability daily and alerts you when a locale starts failing. For a broader review, see our technical SEO audit checklist.

Summary

  • Every page must list all alternates, including itself, and every link must be returned by the target page.
  • Use valid ISO codes: en-gb, not en-uk; language is required, region is optional.
  • Point hreflang only at absolute, canonical, indexable URLs that return 200, and keep self-canonicals on every locale.
  • Keep annotations early in a valid head, avoid forced geo-redirects, and use one consistent delivery method.
  • Audit with a crawler across all locales and confirm in Search Console that the right URLs win in each country.
SharePostLinkedInFacebook

Get Your SEO Audit

Every issue in this article, checked on your site by an auditor and delivered as a prioritized roadmap within 48-72 hours.

See pricing

Related articles