Platform Guides

Hreflang on Shopify: what breaks, and how to stop it breaking

Shopify generates hreflang automatically, and it is correct right up until your setup outgrows one store. Here are the four ways it goes wrong, and how to see what your storefront is really emitting.

10 min read
Free Guide

What hreflang is for

You sell the same product to Australia, the UK and the US. Three URLs, near-identical copy, three prices. Google finds all three and has to decide which one to show a shopper in Manchester.

Hreflang is how you tell it. Each page carries a list of its own alternate versions, tagged by language and optionally by region, and every page in the set carries the same list including itself. Google reads that set and points each searcher at the version meant for them.

That's the whole job. It doesn't help you rank. It doesn't stop duplicate content penalties (which aren't a thing in the way people mean). It sorts out which of your near-identical pages a given person lands on, which matters enormously when the wrong answer shows a Brisbane shopper prices in dollars they can't spend.

The four ways Shopify markets get it wrong

Shopify does generate hreflang for you, automatically, and it does it well. From Shopify's Markets SEO documentation: "Hreflang tags are generated automatically based on your market and language configuration." They're on by default, they update when you change a market, and an x-default tag points at your primary domain. The tags are injected through content_for_header, which your theme already renders in layout/theme.liquid.

So why does anyone have a problem? Because the automation stops at the edge of one store, and most real international setups don't.

1. Missing return links

Google's rule is blunt: "If two pages don't both point to each other, the tags will be ignored. This is so that someone on another site can't arbitrarily create a tag naming itself as an alternative version of one of your pages."

Inside a single store, Shopify handles this for you. Across two stores it can't, because store A has no idea store B exists. If your UK store links to your US store but the US store doesn't link back, Google discards the annotation and you're back to guessing. This is the single most common failure in multi-store setups, and it's silent: nothing errors, nothing warns you, the tags just stop counting.

2. Wrong region codes

The format is ISO 639-1 language, then an optional ISO 3166-1 Alpha 2 region. Google names the specific mistakes.

On invented regions: "If you use codes that are listed as reserved for something else, Google Search ignores that part of the annotation (for example, using EU, UN, or UK in hreflang annotations doesn't have an effect on Google Search)." So en-UK isn't an error you'll see reported. It quietly degrades to en, and your UK page stops being the UK page. The correct code is en-GB.

On region-only codes, Google is explicit: "You can't specify the country code by itself. The first code stands for the language and Google doesn't automatically derive the language from a country code." A bare de means the German language, not Germany. au on its own means nothing useful at all.

3. No x-default

The x-default value covers everyone your set doesn't match: "This value is recommended for specifying the fallback page for users whose language settings don't match any of your site's localized versions." A shopper in Japan hitting a set of en-AU, en-GB and en-US pages needs somewhere sensible to land.

Shopify adds one automatically pointing at your primary domain, which is a reasonable default. Across separate stores, nothing coordinates it, so you can easily end up with three stores each declaring themselves the fallback, or none doing it.

4. Currency-only splits

This one is a design mistake rather than a bug, and it's the one I see most often from teams who set up Markets in a hurry.

Hreflang has no currency dimension. Language and region, and that's the entire vocabulary. So a market that differs from another only by currency has nothing to express. Shopify is straightforward about the consequence: "Hreflang tags are generated only for markets that have a distinct domain, subdomain, or subfolder. If all your markets use the same URL with no language or region distinction, then there aren't any alternate versions to reference."

Shopify also notes that serving multiple currencies on your primary domain alone "won't help you acquire SEO traffic from secondary markets", because no region-specific URLs get created. If your international strategy is currency switching on one domain, that's a perfectly valid commercial choice, it just isn't an SEO one. Don't expect hreflang to do anything for you, because there's nothing for it to do.

How to see what your store is actually emitting

Guessing is the enemy here, and the good news is that Shopify injects hreflang server-side through content_for_header. It's in the raw HTML. No rendering, no JavaScript, no waiting.

View source, or curl. Load a product page, view source, search for hreflang. This is the same thirty-second check I'd use for favicon and touch icon tags on a Shopify theme, and it answers the question completely for one page. Do it on a product, a collection and a blog article, because they don't always behave the same way.

Search Console URL Inspection. This is the one that tells you what Google actually crawled, rather than what your browser sees today. Inspect a URL, then open View crawled page for the raw HTML Googlebot received.

One thing to know before you go looking for it: the International Targeting report is gone. Google deprecated it, and its help page now reads "The International Targeting report has been deprecated" while confirming "Google will continue to support and use hreflang tags on your pages." There is no Google-hosted hreflang validator any more. Google's own debugging advice points at third-party tools with the disclaimer that "These tools are not maintained or checked by Google." So the workflow is: read the markup yourself, or use something that reads it for you.

Why theme-level hreflang goes stale

Plenty of stores carry hand-written hreflang in theme.liquid, usually from an agency build that predates Markets. It works. It also rots.

It rots because it's a snapshot. You add a market on Tuesday, and the theme code still describes Monday's world. Shopify's own guidance is to build from the localization object rather than hardcode anything: "Don't hardcode domains or resource handles. A hardcoded collection or product handle doesn't work, because a resource's handle can differ in each language, and the <head> in layout/theme.liquid renders on every page."

The objects that exist for this are worth knowing by name, because half the snippets floating around use ones that were deprecated years ago:

  • localization.available_languages - the store's published languages, each a shop_locale.
  • localization.available_countries - the countries available on the storefront.
  • shop_locale.iso_code and shop_locale.root_url - the IETF language tag, and the relative root for that locale.
  • shop.published_locales - still current. shop.enabled_locales is deprecated, and so is shop.locale.
  • request.origin - protocol and host, which is how you build absolute URLs.

Shopify doesn't publish an hreflang Liquid snippet, so anything you find in a blog post (this one included) is community code, not vendor code. The objects above are real and current. The loop you wrap around them is yours to own and yours to maintain.

There's a second failure mode with theme code, and it's nastier than staleness: duplication. Shopify warns that "Adding your own tags on top of the automatic ones can produce duplicate or conflicting annotations, which can hurt your store's search ranking." A store with Markets on, a translation app installed, and legacy theme code from 2022 can emit three conflicting sets at once. Every one of them looks fine in isolation.

What our app automates, and what it deliberately doesn't

We build a Hreflang Tags app for Shopify, so treat what follows as interested but accurate. I'd rather describe it narrowly and correctly than sell you something it doesn't do.

The problem it exists for is the cross-store one, and this is Shopify's own framing, from their theme documentation on when you need manual tags: "a setup that Shopify Markets can't coordinate for you, such as linking alternate versions of a page across separate Shopify stores on different domains." That's the gap. Every store in a workspace becomes one reciprocal set, so the return links in failure mode 1 above actually exist.

What it does:

  • Coordinates alternates across separate stores. One workspace, one reciprocal set, return links in both directions.
  • Finds and clears conflicting tags. Markets output, translation apps, hardcoded theme code. It locates the sources and leaves exactly one correct set.
  • Proposes languages and regions by reading each store's Markets configuration, each with a confidence rating, so you review a handful instead of setting hundreds of dropdowns.
  • Matches URLs across stores by SKU, barcode or handle, with a fix queue for conflicts rather than silent failures.
  • Verifies against your live storefront. It fetches your pages and reads the hreflang actually rendered in the HTML, then reruns nightly, because a reused handle or a deleted product breaks a set quietly.

What it touches, since you're installing it on a live store. It reads Markets configuration, and product title, handle, SKU and barcode. Collections, pages, blogs, articles and web-page-enabled metaobjects by title and handle. It does not have access to customers, orders, pricing or inventory - the scopes simply aren't there. It adds no tracking code to your storefront. Publishing needs no theme code edits; clearing conflicts changes one marker-commented line in your theme layout, with a backup taken first and rollback supported.

What it deliberately leaves to you:

The honest caveat: hreflang is a signal

  • Deciding which markets are worth targeting. It proposes, you approve. A confidence rating is not a business decision.
  • Translating your content. Hreflang describes localised pages, it doesn't create them. Pointing de-DE at an English page is a correctly formed tag around a bad experience.
  • Your store architecture. Whether to run one Markets store or five separate stores is a commercial call with tax, fulfilment and merchandising consequences. We handle the consequences for hreflang, not the decision.
  • Making Google obey. Nothing can promise that, which brings us to the caveat.

Google lists hreflang among the inputs it uses, not as an instruction it follows. In its multi-regional documentation it says it "relies on a number of signals to determine the best target audience for a page", and hreflang statements are one item in that list, sitting alongside country-code domains, server location and other signals.

Practically, that means correct hreflang makes the right outcome far more likely and never guarantees it. Google may still show a shopper a different version if its other signals point that way. Anyone promising you guaranteed geo-targeting from tags alone is selling something.

It also means the failure mode is invisible. There's no penalty, no warning, no red box in Search Console. Broken hreflang just stops being counted, and you carry on ranking the way you would have without it. That's exactly why the "verify on the live page" step matters more here than in almost any other technical SEO task.

Next step

Pick one product that exists in every market you sell to. View source on each version. Check three things: does every version list every other version, does each list itself, and is there exactly one x-default.

If those three hold, your hreflang is doing its job and you can stop reading. If they don't, you've found the specific thing to fix, which is a much better position than "our international SEO feels off".

Once that's sorted, the next lever on international stores is usually conversion rather than crawling. Our notes on Shopify checkout branding and live chat cover the part of the journey that happens after the right shopper lands on the right page.