Hreflang Best Practices: 7 Real-World Scenarios and How to Handle Each

No Comments
TL;DR

Hreflang almost never fails because the spec is hard; it fails because real sites have partial translations, canonicalized URLs, migrations and JavaScript frameworks, so this guide walks through 7 real-world scenarios and the exact way to handle each one.

Here is the uncomfortable number. When Ahrefs analyzed 374,756 domains using hreflang, 67% of them had at least one hreflang issue. That figure comes from Patrick Stox's study, the largest of its kind, and it should reframe how you think about international SEO. Two thirds of the sites that deliberately implemented hreflang, sites that knew it existed and cared enough to deploy it, still got something wrong.

The reason is simple. Hreflang is rarely wrong in theory. Everyone can recite the rules: annotate alternates, include yourself, make the tags reciprocal. Where it breaks is in the messy real world, where translations are incomplete, URLs get canonicalized, sites migrate, and templates blast tags onto pages that should never carry them. So instead of restating the spec, let's walk through the seven scenarios where hreflang actually goes sideways in practice, and how to handle each one. If you want the foundational walkthrough first, start with our complete implementation guide and come back.

Scenario 1: Same language, different regions (en-US vs en-GB vs en-AU)

This is the scenario that triggers the most duplicate-content paranoia, and the paranoia is mostly misplaced. Three English pages that are 95% identical, differing only in currency, spelling and shipping details, are exactly what hreflang was built for. Google's documentation explicitly lists "substantially similar content in a single language targeted at different regions" as a valid use case. You do not need to rewrite the Australian page from scratch to avoid a penalty that does not exist.

The real questions are these. First, is the split worth it at all? If the only difference between en-US and en-GB is "color" versus "colour", you are tripling your crawl footprint and maintenance burden for marginal gain. Split when there is a commercial reason: different currency, different product availability, different legal copy, different shipping promises. If none of those apply, one global English page with x-default serves everyone better.

Second, if you do split, the canonical on each regional version must point to itself. The temptation is to canonicalize en-GB and en-AU back to en-US "to consolidate signals". Do not. Hreflang handles the relationship between near-duplicates; the canonical's only job here is to confirm each URL as the indexable representative of itself:

<link rel="canonical" href="https://example.com/en-gb/pricing/" />
<link rel="alternate" hreflang="en-US" href="https://example.com/en-us/pricing/" />
<link rel="alternate" hreflang="en-GB" href="https://example.com/en-gb/pricing/" />
<link rel="alternate" hreflang="en-AU" href="https://example.com/en-au/pricing/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/pricing/" />

Note the self-reference for en-GB on the en-GB page. Every page in the cluster carries the full set, including itself. Miss that, and search engines may discard the whole annotation group.

Scenario 2: Partial translations (20 of 200 pages translated)

You launched a German version, but budget covered only your 20 highest-traffic pages. The other 180 exist only in English. This is where template-driven CMS setups quietly sabotage you: the theme injects the hreflang block sitewide, so 180 English pages now declare a German alternate that is either a 404, a redirect to the German homepage, or worse, an untranslated English page sitting on a /de/ URL.

The rule is strict and unglamorous. Hreflang belongs only on pages that have a real, live, translated alternate. A page with no German version gets no de annotation. Period. The 20 translated pairs each get a clean two-way (or three-way, with x-default) cluster; the 180 English-only pages get either no hreflang at all or, if your template insists, a self-referencing en entry and nothing else.

Pointing German users at an English page on a German URL does not "reserve the territory" for future translation. It tells Google your de alternates are unreliable, it gives German searchers a bait-and-switch, and it inflates your error reports until nobody reads them anymore. Annotate what exists. Add clusters as translations ship. Your hreflang map should be a statement of fact, not a roadmap of ambition.

Scenario 3: Choosing your x-default

x-default answers one question: where should a user go when none of your declared languages match theirs? A searcher in Vietnam, say, when you only have English, German and French versions. It is a fallback for unmatched users, not a "most important page" award, and Google may also serve it when its language detection is unsure.

You have two sane choices. If you have a language selector page, a hub that lets users pick their locale, that is the textbook x-default target. Google's documentation uses exactly this example. If you do not have a selector page, point x-default at the version most likely to be usable by a random human with no matching locale, which in practice usually means your global English page or your biggest market's version.

Three rules keep you out of trouble. One x-default per cluster, not one per language. The x-default URL must itself be indexable and part of the reciprocal set. And it is perfectly fine for the x-default URL to also carry a language annotation; your global English page can be both hreflang="en" and hreflang="x-default". What it cannot be is a page that redirects visitors by IP before they ever see it, which brings us to a related point: automatic IP-based redirection on hreflang targets undermines the whole system, because Googlebot mostly crawls from US IPs and will get bounced like everyone else.

Scenario 4: Hreflang and canonical, the classic collision

If you only fix one thing after reading this article, make it this one. Every URL referenced in an hreflang annotation must be indexable and must carry a self-referencing canonical. The classic break looks like this: your French page canonicalizes to the English page (someone "consolidating duplicate content"), while your English page declares the French URL as its fr alternate. You are now sending Google two contradictory instructions about the same URL. The canonical says "do not index me, I am a copy of the English page". The hreflang says "index me and serve me to French users".

Google resolves contradictions by ignoring somebody, and you do not get to choose whom. Usually the hreflang annotation pointing at the canonicalized URL is simply dropped, your French page never swaps into French results, and you spend a quarter wondering why France converts so badly.

The fix is mechanical. Crawl every URL that appears in any hreflang annotation. For each one, verify three things: it returns 200, it is not blocked from indexing, and its canonical points to itself. Our automated check for a canonicalized URL has incoming hreflang flags exactly this pattern, because it is one of the most common and most damaging failures we see. While you are at it, watch for the sibling problem: the same URL receiving different hreflang values from different pages, which we cover in our check for conflicting hreflang entries. One URL, one language-region identity, everywhere it is mentioned.

Scenario 5: Migrations and redesigns

Site migrations are where tidy hreflang implementations go to die. You restructure the US site, set up your 301s, update internal links, and feel good about yourself. Meanwhile, the German, French and Japanese versions still carry hreflang annotations pointing at the old US URLs, which now redirect. The Ahrefs study found hreflang annotations pointing at redirected or broken URLs to be among the widespread real-world issues, and migrations are the single biggest generator of them.

Why it matters: an hreflang target that 301s is, at best, a hint Google has to resolve through an extra hop, and at worst a signal that gets discarded along with its return tag, unraveling the cluster. A target that 404s is worse; the annotation is dead weight and the reciprocity for every other page in the cluster is broken.

The handling is a checklist, and it must run before launch, not after:

Migration hreflang checklist
1. Export every hreflang annotation across ALL locales,
   not just the one being migrated.
2. Map old URL to new URL for every migrated page.
3. Update annotations ON the migrated pages
   (their own clusters, including self-references).
4. Update annotations POINTING AT the migrated pages
   from every other locale (the return tags).
5. Regenerate hreflang sitemaps from the new URL set.
6. Post-launch: crawl all hreflang targets,
   assert 200 status and self-canonicals.

Step 4 is the one teams forget, because it lives outside the migrated section. Migrating example.com/us/ means editing pages in /de/, /fr/ and /jp/ too. If your annotations live in a sitemap generated from one database (see scenario 7), this is a non-event. If they are hand-edited into 14 templates, schedule a long week.

Scenario 6: JS-injected hreflang on SPAs

Your React or Vue app injects hreflang tags client-side, the SEO plugin demo looked great, and view-source shows nothing. Technically, Google can pick up hreflang from rendered HTML; rendering is part of its indexing pipeline. Practically, you have taken a signal that needs to be perfectly consistent across hundreds of URL pairs and made it dependent on a rendering queue, your JavaScript executing flawlessly, and no script error firing before the tags mount. Hreflang processing is already one of the slower, more fragile parts of indexing. Adding a rendering dependency on top is volunteering for trouble.

There is also a verification cost: every audit now requires comparing raw HTML against rendered HTML for every locale, and most monitoring tools and other search engines read the raw response. Bing and Yandex are notably less enthusiastic about rendering than Google.

The handling: ship hreflang server-side, full stop. If you have SSR or static generation, emit the link tags in the initial HTML response. If the front end genuinely cannot be changed, bypass the HTML entirely and declare hreflang in your XML sitemaps instead, which search engines read without rendering anything. Either way, pick one home for the annotations; do not let a JS plugin inject one set while the sitemap declares another, or you will manufacture the conflicting-entries problem from scenario 4. For a breakdown of the three valid methods and when each fits, see our guide on where to declare hreflang.

Scenario 7: Scale, or hreflang for 30+ locales

At 3 locales, hreflang in the HTML head costs three link tags per page. At 30 locales, every page carries 31 annotations (each locale plus x-default), times every page on the site, times every change. That is real HTML bloat on every response, and one quiet CMS misconfiguration in the Korean template can break return tags for all 30 siblings at once. Hand-writing this is not a workflow, it is a countdown.

The handling has two parts. First, move the annotations into XML sitemaps, which is where large international sites almost universally end up. The syntax puts the full alternate set inside each url entry:

<url>
  <loc>https://example.com/en-us/pricing/</loc>
  <xhtml:link rel="alternate" hreflang="en-US"
    href="https://example.com/en-us/pricing/" />
  <xhtml:link rel="alternate" hreflang="de-DE"
    href="https://example.com/de-de/preise/" />
  <!-- ...28 more locales... -->
  <xhtml:link rel="alternate" hreflang="x-default"
    href="https://example.com/pricing/" />
</url>

Second, and more important: generate, never hand-write. The sitemap should be built programmatically from a single source of truth, a translation table or locale registry that knows which page exists in which locale. Generation makes reciprocity automatic (every member of a cluster gets the same set), makes partial translations safe (no row in the table, no annotation), and turns migrations into a regeneration job instead of an archaeology project. It also enforces the one-method rule: if the sitemap is the source of truth, strip hreflang from the HTML head entirely so the two can never disagree.

The rules that never change

Every scenario above is a variation on a handful of invariants. Tape these to the monitor:

  • Self-reference always. Every page's annotation set includes the page itself.
  • Reciprocity always. If A names B as an alternate, B must name A back, or the annotations may be ignored.
  • Absolute URLs always. Full protocol and host, never relative paths.
  • Correct ISO codes. Language in ISO 639-1, optional region in ISO 3166-1 Alpha 2, in that order: en-GB, not gb-EN, not en-UK.
  • One declaration method. HTML head, HTTP headers, or XML sitemap. Pick one and retire the others.

Break any of these and you are back in the 67%. For a full tour of the failure modes around reciprocity and fallbacks, our return tag and x-default errors deep dive goes issue by issue.

FAQ

Q: Does hreflang directly improve rankings?

A: No. Hreflang is a swap mechanism, not a ranking signal. Your pages rank on their own merits; hreflang tells Google which version of an already-ranking cluster to show a given user. The indirect win is real, though: the right language in front of the right user means better engagement and fewer pogo-sticks back to the results.

Q: Can I use hreflang between two different domains?

A: Yes. Hreflang works across domains, subdomains and subfolders alike, so example.de and example.com can reference each other. The same rules apply: absolute URLs, full reciprocity in both directions, and self-canonical targets on both sides. Cross-domain setups just fail more quietly, since two teams now have to keep the clusters in sync.

Q: How long until hreflang fixes show results?

A: Google has to recrawl both sides of every pair before it trusts a cluster, so expect weeks, not days, with timing driven by your crawl rate. Resubmitting updated hreflang sitemaps in Search Console speeds discovery. Measure success by impressions in the target country and by the correct URL appearing in local results, not by overnight rank jumps.

Need your international setup audited?

SEO ProCheck runs deep hreflang and international SEO audits.

Get in touch

Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.

    About SEO ProCheck

    Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.

    Work With Me

    Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.

    Subscribe to our newsletter!

    More from our blog