Hreflang guide: implementation, common errors and a Shopify Plus fix

Send me an e-mail

Short answer: hreflang is a tag that tells Google which language and country each version of a page is for, so a searcher in Germany gets your German page and a searcher in the UK gets your UK page. Every version must list all the others and itself, use valid codes such as de-DE or en-GB, and point only to live, indexable URLs. Hreflang does not fix duplicate content; it helps Google pick the right version for each market.

Below: the code for the three ways to add hreflang, the errors that quietly break it, how Shopify Markets, Webflow, WordPress and custom JavaScript platforms handle it, and two real fixes: a Shopify Plus store and a React shop where JavaScript doubled every tag.

How hreflang works

Each language or country version of a page is an "alternate". On every alternate you list the full set: the other versions plus the page itself. Google only trusts a pair when both pages confirm each other (a "return link"). If page A points to page B but B does not point back, Google ignores that pair.

The code has two parts: a language in ISO 639-1 format (de, en, nl) and, optionally, a country in ISO 3166-1 alpha-2 format (DE, GB, BE). You can target a language alone (de), or a language in a country (de-AT), but never a country alone. Add x-default for the page people should get when none of your versions match, usually a language picker or your main international version.

Three ways to add hreflang

Pick one method per site and use it everywhere. Mixing methods is allowed, but if the head tags and the sitemap disagree, you create the errors you were trying to avoid.

1. Link tags in the HTML head

The most common method. This is the head of the German product page:

<!-- on https://example.com/de-de/schuhe/ -->
<link rel="canonical" href="https://example.com/de-de/schuhe/" />
<link rel="alternate" hreflang="de-DE" href="https://example.com/de-de/schuhe/" />
<link rel="alternate" hreflang="de-AT" href="https://example.com/de-at/schuhe/" />
<link rel="alternate" hreflang="en-GB" href="https://example.com/en-gb/shoes/" />
<link rel="alternate" hreflang="nl-NL" href="https://example.com/nl-nl/schoenen/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/shoes/" />

The canonical points to the page itself, and the German page lists itself as de-DE. The UK, Austrian and Dutch pages carry the same five alternate lines, each with its own self-referencing canonical.

2. XML sitemap

Better for large sites, because it keeps the page head small and puts every set in one file you can check:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <url>
    <loc>https://example.com/de-de/schuhe/</loc>
    <xhtml:link rel="alternate" hreflang="de-DE" href="https://example.com/de-de/schuhe/" />
    <xhtml:link rel="alternate" hreflang="en-GB" href="https://example.com/en-gb/shoes/" />
    <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/shoes/" />
  </url>
  <!-- repeat a <url> block for /en-gb/shoes/ and /shoes/ with the same three lines -->
</urlset>

3. HTTP headers

For files without an HTML head, such as PDFs:

Link: <https://example.com/de-de/preisliste.pdf>; rel="alternate"; hreflang="de-DE",
      <https://example.com/en-gb/price-list.pdf>; rel="alternate"; hreflang="en-GB"

The errors that break hreflang

Hreflang rarely fails loudly. Google just ignores the broken pairs and keeps showing the wrong version. These are the problems I find most often in audits:

ErrorWhat happensFix
Invalid code, e.g. en-UKThe tag is ignored. UK is not a country code; uk as a language means UkrainianUse en-GB
Country without language, e.g. be meant as BelgiumRead as the language Belarusian, or ignoredUse nl-BE or fr-BE
No return linkGoogle ignores the pairEvery alternate lists every other alternate
No self-referenceThe set is incompleteEach page lists itself too
Canonical points to another language versionThe local page drops out of the index; hreflang is ignoredCanonical to the page itself
Alternates that redirect, 404 or are noindexThose pairs are droppedOnly list live, indexable, canonical URLs
Relative URLsUnreliableAlways use full URLs with https://
Two sources of tags, e.g. theme plus translation appDuplicate or conflicting setsLet one system output hreflang
JavaScript adds a second set after the page loadsTwo canonicals and a double hreflang set in the rendered page, while the server HTML looks fineLet the script replace the server tags, and test the rendered page
Translated page, untranslated meta titleRight page, wrong-language snippet, low CTRTranslate SEO titles and descriptions per locale

Hreflang on Shopify, Webflow and WordPress

Shopify and Shopify Markets

Shopify adds hreflang tags automatically for the languages and markets you publish, as subfolders (/de-de/) or separate domains. Most problems come from what sits on top: a translation app that adds a second set of tags, a theme with hard-coded alternate links, or markets where the language is not published. Check the rendered head of a few pages per market and make sure only one set appears. Also translate the SEO title and meta description in Translate & Adapt (or your translation app); Shopify does not do that for you.

Webflow

Webflow Localization adds hreflang tags automatically for every published locale, so on localized sites the job is checking, not coding: confirm each locale is published and do not add manual tags on top. Sites without Localization that run separate language pages need the link tags in each page's custom code head, or built from CMS fields on collection templates.

WordPress

WordPress has no built-in multilingual setup, so hreflang comes from the plugin that manages translations, such as WPML, Polylang or TranslatePress. Make sure your SEO plugin is not adding its own set as well, and recheck after plugin updates.

Custom JavaScript platforms (React, Next.js, single-page apps)

On a custom platform you build hreflang yourself, and the risk is not the server but the browser. Many sites render the head on the server and then let a JavaScript component manage the tags after the page loads. If that component only removes the tags it created itself, the server's tags stay and a second set is added next to them.

Example from a 2026 audit. A Dutch food-delivery shop selling in five languages moved from Shopify to its own React platform. A plain request (curl) showed a correct head. In the browser, after JavaScript, the same pages had two canonicals and 12 hreflang tags instead of one and six. The same component also replaced the page title with the bare brand name on 1,110 of the 1,165 URLs in the sitemap. The developer changed the component so it replaces the server tags instead of adding to them, live on 13 September 2026. A crawl with JavaScript rendering on 2 October 2026 found one canonical and six hreflang tags (nl, en, tr, de, fr, x-default) on 1,224 of 1,228 indexable pages, every page referring to itself, and no missing return links or alternates pointing to non-200 URLs. The other four pages only exist in Dutch and correctly carry nl and x-default.

The lesson: I first blamed server-side rendering, because the server response and the browser tab disagreed. Check both. A source-code check alone misses tags that JavaScript adds; a browser check alone misses what crawlers that do not run JavaScript receive.

Choosing between subfolders, subdomains and country domains is a separate decision; I compare them in international SEO: subdirectories vs hreflang.

How to test hreflang

Search Console no longer reports hreflang errors: Google removed the International Targeting report in 2022. Test it yourself instead:

  1. Crawl the site with Screaming Frog (hreflang tab), Ahrefs Site Audit or Semrush Site Audit. Look for missing return links, non-200 alternates, invalid codes and canonical conflicts.
  2. Spot-check the rendered head of one page per market in your browser's developer tools, as in the Muchachomalo screenshot below. Apps often inject tags that never show up in theme files.
  3. On JavaScript sites, count the tags after loading. Paste this in the browser console and compare the numbers with the server response from curl:
    document.querySelectorAll('link[rel="canonical"]').length            // should be 1
    document.querySelectorAll('link[rel="alternate"][hreflang]').length  // one per version
  4. Check Google's choice with URL Inspection in Search Console: the Google-selected canonical should be the local page, not another language version.
  5. Check the snippets: search from each target country (or with a VPN) and confirm the title and description appear in the right language.

Hreflang is one part of a wider check; the technical SEO audit guide covers the rest.

Case: fixing hreflang on Muchachomalo (Shopify Plus)

The problem. Muchachomalo, a Dutch underwear brand, sells across Europe on Shopify Plus. German searchers were seeing English meta titles, and the wrong language versions ranked in several countries. The self-referencing hreflang tags were missing, so Google did not treat the regional versions as a complete set. As a result, click-through rate in the international markets was underperforming.

The fix. We moved to a strict subfolder structure per market, corrected the hreflang output in the Shopify theme so every page listed all alternates plus itself, set each local page's canonical to itself, and localized the meta titles and descriptions, starting with Germany:

  • Meta title (58 characters): Muchachomalo Herren-Boxershorts: Premium-Qualität & Design
  • Meta description (152 characters): Shoppen Sie Muchachomalo Boxershorts online. Einzigartige Designs, perfekte Passform und langlebige Qualität. Jetzt versandkostenfrei ab 50 € bestellen!
Chrome DevTools showing the hreflang link tags in the head of muchachomalo.com, from x-default to the country and language variants
The hreflang link tags in the head of muchachomalo.com, including x-default, as seen in Chrome DevTools.

The result. German searchers started seeing German titles and descriptions, and international organic traffic grew in the months after the fix. The exact figures from that period are not included here.

Questions people ask

Does hreflang fix duplicate content? No. Pages that are nearly identical across countries, such as UK and Irish English pages, are not a penalty risk anyway. Hreflang tells Google which of them to show where; the canonical decides which URL gets indexed.

Do I need x-default? It is not required, but recommended whenever you have a fallback: a language picker, or one version meant for everyone outside your target markets.

Is it en-GB or en-UK? en-GB. Country codes follow ISO 3166-1, where the United Kingdom is GB.

Can hreflang point to another domain? Yes. Alternates can sit on country domains such as example.de and example.nl, as long as every domain returns the links.

Does hreflang work on JavaScript sites? Yes, but put the tags in the server HTML and make sure scripts do not add a second set after loading. Test the rendered page, not only the source.

Should I use the head or the sitemap? The head is easier to check page by page; the sitemap scales better for large catalogues. Use one, consistently.

Working on an international Shopify or Webflow store? Email me for an hreflang check. For how this fits AI search, read how GEO and SEO fit together in 2026.