Hreflang Implementation: Mistakes and How to Avoid Them

The bidirectionality rule + sitemap-vs-tag choice are where most sites lose it

Enric Ramos · · 8 min read
a computer screen with a rocket on top of it

Hreflang breaks silently. Unlike most SEO misconfigurations, bad hreflang doesn't generate alerts in Search Console, doesn't show up as errors in most audit tools, and doesn't cause visible ranking drops. What it causes is underperformance in secondary markets — users in the UK landing on the US version, Spanish users landing on Mexican content, the wrong currency shown — with nobody sure why the conversion rate is off.

This article covers implementation patterns that work, the bidirectionality requirement most sites get wrong, and the top 10 mistakes I see in international SEO audits.

The three delivery methods

Hreflang can be delivered three ways. Pick one for your site and stick with it.

<link rel="alternate" hreflang="en-us" href="https://example.com/en-us/page" />
<link rel="alternate" hreflang="en-gb" href="https://example.com/en-gb/page" />
<link rel="alternate" hreflang="es-es" href="https://example.com/es-es/page" />
<link rel="alternate" hreflang="x-default" href="https://example.com/en-us/page" />

Each page lists all its language/region alternates, including itself (self-reference is required).

When to use: Sites with 2-6 locales and reasonable number of pages (under 10,000). Simple, readable.

Limitations: Scales poorly. With 8 locales and 50,000 pages, you're maintaining 400,000 <link> tags across templates.

For non-HTML resources (PDFs):

Link: <https://example.com/en-us/doc.pdf>; rel="alternate"; hreflang="en-us",
      <https://example.com/es-es/doc.pdf>; rel="alternate"; hreflang="es-es"

Rarely the primary method for HTML content; usually the supplement for non-HTML assets.

Method 3: XML sitemap annotations

<url>
  <loc>https://example.com/en-us/page</loc>
  <xhtml:link rel="alternate" hreflang="en-us" href="https://example.com/en-us/page" />
  <xhtml:link rel="alternate" hreflang="en-gb" href="https://example.com/en-gb/page" />
  <xhtml:link rel="alternate" hreflang="es-es" href="https://example.com/es-es/page" />
  <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/en-us/page" />
</url>

When to use: Sites with 5+ locales and / or 10,000+ pages. The only method that scales cleanly — you declare all cross-references in one XML file that's easy to generate, validate, and update.

Recommended for: Any medium-to-large multilingual site. This is what I default to in audits.

Warning: don't mix methods on the same URL. If a URL has <link rel="alternate"> tags AND is listed with <xhtml:link> in the sitemap, and they disagree, behavior is undefined. Pick one source of truth.

The bidirectionality requirement

This is the #1 mistake in hreflang implementations.

If URL A declares URL B as the es-es alternate, then URL B must declare URL A as the equivalent alternate for B's language. The references must be bidirectional, or hreflang is silently ignored.

Example — correct:

Page /en-us/shoes:

<link rel="alternate" hreflang="en-us" href="/en-us/shoes" />
<link rel="alternate" hreflang="es-es" href="/es-es/zapatos" />
<link rel="alternate" hreflang="x-default" href="/en-us/shoes" />

Page /es-es/zapatos:

<link rel="alternate" hreflang="en-us" href="/en-us/shoes" />
<link rel="alternate" hreflang="es-es" href="/es-es/zapatos" />
<link rel="alternate" hreflang="x-default" href="/en-us/shoes" />

Both pages reference each other and themselves. Google validates; if cross-references don't match, hreflang for those pages is ignored.

Example — broken:

Page /en-us/shoes references /es-es/zapatos but page /es-es/zapatos references /es-es/zapatillas (a different URL). The reference breaks. Googlebot may still show either URL to either audience; you've lost control.

Validation: Search Console's International Targeting report shows hreflang errors (URL references that don't reciprocate). Check weekly; fixing errors here often causes visible improvement in secondary-market rankings within a week.

Region codes: getting them right

Hreflang uses:

  • ISO 639-1 two-letter language codes (en, es, fr, de, zh, ja).
  • ISO 3166-1 Alpha 2 two-letter country codes (US, GB, MX, DE, JP).

Format: language-region, with region optional.

en          # English, any region
en-us       # English for US users
en-gb       # English for UK users
es          # Spanish, any region
es-mx       # Spanish for Mexico
es-es       # Spanish for Spain
zh          # Chinese, any variant
zh-cn       # Simplified Chinese for China
zh-tw       # Traditional Chinese for Taiwan

Common code mistakes:

  • en-uk — wrong. UK is not an ISO country code. Use en-gb (Great Britain).
  • en-eu — wrong. EU is not a country. Use en for any English-speaking user without a specific region.
  • zh-hk — for Hong Kong specifically. Different from zh-cn (Mainland).
  • pt-br vs pt-pt — Brazilian vs European Portuguese. Very different; use the right one.
  • en-au for Australia — correct. en-nz for New Zealand.

When in doubt, consult ISO 3166 country codes list.

x-default semantics

x-default marks the fallback URL for users whose language/region doesn't match any declared alternate.

<link rel="alternate" hreflang="x-default" href="/en-us/page" />

When to use:

  • Always on multilingual sites. If you declare en-us, es-es, de-de, you need an x-default for users speaking, say, French or Japanese.
  • Typically points to the "international" version — either the English version that serves as the default, or a dedicated /international/ page with language selector.

Without x-default, Google picks based on its own heuristics for users outside your declared markets. Often picks suboptimally.

Common mistakes (top 10)

1. Missing self-reference

Each URL must declare itself as an hreflang alternate. Some audit tools catch this; many don't.

Wrong (on /en-us/page):

<link rel="alternate" hreflang="es-es" href="/es-es/page" />
<!-- no self-reference -->

Right:

<link rel="alternate" hreflang="en-us" href="/en-us/page" />  <!-- self -->
<link rel="alternate" hreflang="es-es" href="/es-es/page" />

2. Broken bidirectionality

Covered above. Most common source: URL changes in one language that don't propagate to alternates.

3. Absolute URLs with inconsistent protocol or host

<link rel="alternate" hreflang="en-us" href="http://example.com/en-us/page" />  <!-- HTTP -->
<link rel="alternate" hreflang="es-es" href="https://example.com/es-es/page" />  <!-- HTTPS -->

Must be consistent. Always use absolute URLs (full https://host/path). Relative URLs are technically allowed but invite bugs.

4. Canonical vs hreflang conflicts

Each locale URL should self-canonical, not cross-canonical. Wrong:

<!-- On /es-es/zapatos -->
<link rel="canonical" href="/en-us/shoes" />  <!-- canonicaling across locales -->
<link rel="alternate" hreflang="es-es" href="/es-es/zapatos" />

This tells Google "the Spanish page is a duplicate of the English one; also, the Spanish page serves Spanish users." Google picks one and ignores the other. Fix: self-canonical each locale.

5. Wrong region codes

en-uk instead of en-gb. Common.

6. Missing x-default

Fine for monolingual sites. For multilingual, its absence creates ambiguity.

7. Hreflang to redirects

If URL A has hreflang="es-es" pointing to URL B, and URL B redirects to URL C, the hreflang signal gets weakened. Always point to the final canonical URL.

8. Too many locales

Some sites declare 20+ locales because the CMS supports them, even though content is mostly identical. Google processes this fine, but you create maintenance burden and increase the risk of bidirectionality errors. Use specific locales only when content is genuinely localized.

9. Language-only vs language+region confusion

en is "any English user"; en-us is "US English users specifically." On a site with only one English version, use en (simpler, matches more users). If you have truly different US and UK English versions (pricing, spelling, product availability), use en-us and en-gb with en as the fallback.

10. Mixing delivery methods

Don't put hreflang in <link> tags AND the sitemap. Pick one. When they conflict, Google's behavior is undefined and debugging is a nightmare.

Validation workflow

Pre-deploy:

  • Run your crawler (Screaming Frog, Sitebulb) with hreflang validation enabled.
  • Check for bidirectionality errors, missing self-references, invalid codes.
  • Check that all hreflang URLs return 200 (not 404 or redirects).

Post-deploy:

  • Search Console → International Targeting report. Check hreflang error count.
  • Log analysis: are the correct locale URLs getting Googlebot visits? (A new hreflang implementation often redistributes crawl attention.)
  • Monitor organic traffic per locale for 2-4 weeks. Significant shifts (positive or negative) indicate hreflang is working or misconfigured.

Ongoing:

  • Weekly check of Search Console International Targeting report.
  • Automated test in CI: for any changed page, verify all hreflang alternates still return 200 and still reference back.

The sitemap pattern for scale

For sites past 10,000 pages or 6+ locales, sitemap-delivered hreflang is the only reasonable choice. Template:

<?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-us/shoes</loc>
    <xhtml:link rel="alternate" hreflang="en-us" href="https://example.com/en-us/shoes" />
    <xhtml:link rel="alternate" hreflang="en-gb" href="https://example.com/en-gb/shoes" />
    <xhtml:link rel="alternate" hreflang="es-es" href="https://example.com/es-es/zapatos" />
    <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/en-us/shoes" />
  </url>
  <url>
    <loc>https://example.com/en-gb/shoes</loc>
    <xhtml:link rel="alternate" hreflang="en-us" href="https://example.com/en-us/shoes" />
    <xhtml:link rel="alternate" hreflang="en-gb" href="https://example.com/en-gb/shoes" />
    <xhtml:link rel="alternate" hreflang="es-es" href="https://example.com/es-es/zapatos" />
    <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/en-us/shoes" />
  </url>
  <!-- etc, one <url> per locale URL -->
</urlset>

Auto-generate this from your database or CMS. Validate the generator output with a unit test — a sitemap generator bug is the #1 way hreflang regressions happen.

Frequently asked questions

If my content is identical across locales, do I still need hreflang?

If the URL differs per locale, yes — without hreflang, Google treats them as duplicates and picks one, potentially the wrong one for each user. Hreflang tells Google "these are all correct, just for different audiences."

What if a URL doesn't exist in all locales?

Only include hreflang for locales where the URL exists. It's fine for /shoes to exist in en-us and es-es but not fr-fr — just don't declare fr-fr as an alternate for that URL.

Does hreflang affect rankings?

Not directly. Hreflang is a targeting signal that reshuffles which of your URLs ranks for which audience. Rankings for the target queries are still driven by the usual signals (content quality, backlinks, engagement).

Can I use hreflang between subdomain and subdirectory?

Yes. es.example.com/pagina can be the es-es alternate of example.com/en-us/page. Google handles cross-subdomain hreflang fine.

How long does hreflang take to take effect?

Faster than most SEO signals — typically 1-3 weeks from implementation to observable change in SERP behavior per locale. Monitor per-country organic traffic in Google Analytics + Search Console per-country filter.

Related articles

a computer screen with a rocket on top of it

The Complete Guide to Technical SEO Audits

Most technical SEO audits fail the same way: they generate 80-page PDFs with 200 findings, and clients execute none of them. The audits that move rankings solve for one thing: which of five layers is broken, and which single fix restores the most value.

· 11 min read
a computer screen with a rocket on top of it

Core Web Vitals in 2026: What Still Matters

Core Web Vitals is a real but modest ranking signal — and the metrics keep shifting. INP replaced FID in March 2024. Here's what the current three metrics actually measure, what they don't, and where optimization actually moves the needle.

· 9 min read