Fixing Hreflang and Canonical Conflicts
Hreflang says "these pages are alternatives for different audiences". A canonical tag says "this page is a copy; index that one instead". When a French page carries hreflang for itself but a canonical pointing at the English page, the two signals contradict each other, and Google usually sides with the canonical.
The French page then drops out of the index and the cluster has nothing to show French searchers. The same clash appears in quieter forms, such as a canonical that differs from the hreflang address by a slash or a parameter. This guide explains each form and how to line them up.
What the conflict looks like
The classic form is a translated page that names the original language as its canonical. It often starts as an attempt to "avoid duplicate content" across translations, which translations do not need:
<!-- On https://example.com/fr/tarifs/ : wrong -->
<link rel="canonical" href="https://example.com/pricing/">
<link rel="alternate" hreflang="en" href="https://example.com/pricing/">
<link rel="alternate" hreflang="fr" href="https://example.com/fr/tarifs/">
Here the page claims to be the French alternative and, in the line above, claims to be a copy of the English page. Google cannot do both. Fixed, each page names itself as canonical, and the hreflang lines are unchanged:
<!-- On https://example.com/fr/tarifs/ : right -->
<link rel="canonical" href="https://example.com/fr/tarifs/">
<link rel="alternate" hreflang="en" href="https://example.com/pricing/">
<link rel="alternate" hreflang="fr" href="https://example.com/fr/tarifs/">
Google's guidance on canonicalisation is that localised versions of a page are only treated as duplicates if the main content is left untranslated. A properly translated page is a separate page and should be canonical to itself.
The five forms of the conflict
The cross-language canonical is the easiest to spot. The others look harmless because the two addresses are almost the same, but to Google they are different URLs.
| Form | Canonical says | Hreflang says | Effect |
|---|---|---|---|
| Cross-language canonical | /pricing/ on the French page | /fr/tarifs/
is the French version | French page folded into English; cluster loses French |
| Trailing slash or case | /fr/tarifs | /fr/tarifs/ | Hreflang names a non-canonical address, so Google may not use it |
| Protocol or host | https://www.example.com/fr/tarifs/ | https://example.com/fr/tarifs/ | Same as above, across every page at once |
| Parameter version | /fr/tarifs/ | /fr/tarifs/?currency=eur | Hreflang points at a page that declares itself a copy |
| Everything to x-default | The language picker on every locale page | Separate pages per locale | All locales folded into the picker |
The rule that covers all five: the address in each hreflang line must be exactly the address that page declares as its canonical, character for character, and each locale page must declare itself.
Where the wrong canonical usually comes from
- A theme or plugin that sets the canonical from the "original" post. Some multilingual setups store translations as linked copies of a source post, and a canonical routine written before the site was multilingual reads the source post's address.
- A hard-coded canonical in a shared layout. A developer adds
<link rel="canonical" href="https://example.com/">to the base template, and every page in every language claims to be the home page. - A base URL setting per environment. The canonical is built from one setting and
hreflang from another, so one uses
wwwand the other does not, or one adds a trailing slash. - Currency or country parameters. Shops that switch currency with
?currency=or?country=sometimes feed that address into hreflang while the canonical correctly strips it. - Two tools both writing tags. A translation plugin outputs hreflang, an SEO plugin outputs canonicals, and they build addresses differently.
- Deliberate consolidation that was never finished. Someone decided to merge thin regional pages into one, set canonicals to the main version, but left the old pages in the hreflang cluster.
Same-language regional versions
The trickiest case is not a mistake in the tags at all. If your British, Irish and Australian pages are all in English and almost identical, each can correctly be canonical to itself and Google may still decide they are duplicates and pick one of them as the canonical for the group. URL Inspection will show "Google-selected canonical" as a different address from the one you declared.
Hreflang can still help here: Google may continue to show the local address to searchers in each country even when it has grouped the pages. But you are relying on Google's judgement, and the clearer fix is to make the versions meaningfully different:
- Show local prices and currency in the HTML, not only after a script runs.
- Use local delivery times, returns terms, contact numbers and business addresses.
- Adjust spelling and vocabulary where it differs, such as colour and color or postcode and zip code.
- Where the content really is identical for everyone, drop the regional split and use one page with plain
en.
Diagnosing the conflict page by page
The Hreflang Checker compares the canonical on each target with the address the cluster uses for it. To confirm one page by hand, pull both sets of tags out of the served HTML:
curl -s https://example.com/fr/tarifs/ | grep -Eio '<link[^>]+rel="(canonical|alternate)"[^>]*>'
Read the canonical line first, then find the hreflang line for the page's own language. They should match exactly. Then open each other address in the cluster and repeat, because a conflict on one locale affects the others.
For a view of what Google has actually done, use URL Inspection in Search Console. It shows the canonical you declared and the one Google selected. When they differ on a translated page, the page is being folded into another; when they differ on a same-language regional page, see the section above.
Where to change it on common platforms
- WordPress with WPML or Polylang. Yoast SEO, Rank Math and similar plugins normally
output a self-referencing canonical for each translation. If yours points at the source language, look
for a custom filter on the canonical in the theme's
functions.php, or a WPML setting that treats untranslated content as a copy of the original. See the WordPress hreflang guide. - Shopify. Themes output the canonical through
canonical_url, which is locale-aware. Conflicts usually come from a hard-coded canonical added totheme.liquid, or from an app adding its own tags. The Shopify hreflang guide has more. - Next.js App Router. Set
alternates.canonicalandalternates.languagesin the samegenerateMetadatacall from the same locale-aware function, so they cannot disagree. Details are in hreflang in Next.js and Nuxt. - Custom and static sites. Build both the canonical and every hreflang address with one helper that takes a locale and a path and applies the same host, protocol, slash and case rules.
// One helper for both tags, so they cannot drift apart
function localeUrl(locale, path) {
const base = "https://example.com";
const prefix = locale === "en" ? "" : "/" + locale;
const clean = path.replace(/\/+$/, "") + "/";
return (base + prefix + clean).toLowerCase();
}
For canonical problems that have nothing to do with language, such as duplicate product addresses, the general guide to canonical conflicts is the better starting point.
The fix, step by step
Step 1
Compare canonical and hreflang addresses
Run the Hreflang Checker across each locale and list every page where the canonical does not exactly match the address the cluster uses for that page. Group the results by form: a canonical pointing to another language, a slash or case difference, a different host or protocol, a parameter version, or every locale pointing at the x-default page. The form tells you where the fault lives, and one template fix often clears hundreds of rows.
Step 2
Find where the wrong canonical comes from
Fetch the raw HTML of one affected page and see how many canonical tags it has; two tags usually means two tools are writing them. Then trace the one that is wrong to its source: the SEO plugin, the translation plugin, a hard-coded line in the base layout, a theme filter, a framework metadata file or a tag manager. Fix the source rather than patching pages, or the error returns with the next page you publish.
Step 3
Make every locale page canonical to itself
Change the canonical so each translated or regional page names its own address, never the source language, the home page or the language picker. If the page is genuinely meant to be merged into another, redirect it instead and remove it from the cluster, because a page that is both an alternative and a copy sends Google two answers. Make sure only one canonical tag remains in the served HTML after the change.
Step 4
Use canonical addresses inside hreflang
Build every hreflang address with the same function that builds the canonical, so the protocol, host, trailing slash, letter case and path are identical. Strip tracking, currency, sort and session parameters from hreflang addresses. After this step the hreflang line for a page's own language should be a character-for-character copy of its canonical, and the same should be true for every other address in the cluster when you open it.
Step 5
Handle filtered and paginated versions
Decide which addresses belong in clusters at all. Filtered, sorted and search result pages usually canonicalise to a clean listing and should carry no hreflang of their own. Paginated series can keep self-canonicals on each page, with hreflang linking page two in one language to page two in another. Never point hreflang at an address whose canonical names a different page, because that entry will be discarded.
Step 6
Check which canonical Google has chosen
After deploying, inspect a sample of the fixed pages in Search Console and compare the declared canonical with the Google-selected one. Request indexing for key pages. Translated pages should settle on their own address as Google recrawls them. If same-language regional pages are still grouped under one canonical, add genuine local differences or consolidate them. Run the Hreflang Checker again to confirm canonical alignment across every cluster.
Preventing the conflict from returning
- One source of truth for addresses. Canonical, hreflang, sitemap and language switcher links should all come from one address-building function or one plugin, never two.
- A deploy check. For a sample page in each locale, fail the build if the canonical differs from the page's own hreflang line.
- No canonical in shared layouts. Canonicals belong in page-level metadata, where they know the page's own address.
- Consolidate with redirects. When retiring a locale, redirect it and remove it from clusters in the same release.
1. Should translated pages have a canonical pointing to the original language?
No. A translated page is a different page for a different audience, so its canonical should point to itself. Pointing the canonical at the original tells Google the translation is a duplicate, and Google tends to follow the canonical, so the translation may drop out of the index and never be shown to the searchers it was written for. Google's own guidance is that localised versions are only treated as duplicates when the main content has not been translated.
2. Does a trailing slash difference really count as a conflict?
Yes. To Google, /fr/tarifs and /fr/tarifs/ are two different addresses, even if your server shows the same page for both. If the canonical names one and hreflang names the other, hreflang is pointing at a URL the page itself says is not the main version, and the annotation may be ignored. The same goes for http and https, www and non-www, and upper and lower case in the path. Build all addresses with one function to avoid it.
3. Google chose a different canonical for my en-GB and en-IE pages. What now?
When same-language regional pages are nearly identical, Google may group them and pick one as the canonical even though each declares itself. Hreflang can still help Google show the right local address, but you are depending on its judgement. The clearer fix is to make each version genuinely local, with prices, currency, delivery terms and contact details in the HTML. If the pages really are the same for everyone, consider a single page with plain en instead.
4. Can hreflang and canonical tags point to different pages at all?
Yes, and they normally do. On a French page the canonical points to the French page itself, while the hreflang lines point to the French page and to all the other language versions. The only address that must match is the page's own: its canonical and its own-language hreflang line should be identical. The conflict arises when the canonical points to another page in the cluster, or to an address that differs from the one hreflang uses.
5. Should the x-default page be the canonical for all locales?
No. The x-default is simply another member of the cluster, used for visitors who match none of your locales. Pointing every locale's canonical at it tells Google that all your translations are copies of the language picker or the international page, which collapses the cluster. The x-default page should be canonical to itself, and each locale page should be canonical to itself. The x-default address appears in hreflang, never in other pages' canonicals.
6. Our shop uses a currency parameter. Which address goes in hreflang?
Use the clean address that the page declares as canonical, without the currency parameter. If you want different prices for different countries to be found in search, give each country its own path or domain, such as /ie/ and /uk/, with its own canonical and its own hreflang entry. A parameter that only switches currency on one address cannot be a separate hreflang target, because the canonical tells Google all those versions are the same page.
7. How long does it take Google to accept the corrected canonicals?
It depends on how often Google recrawls the pages. Important pages may be updated within days, while deeper pages can take several weeks, and translated pages that had been folded into another language have to be recrawled and reassessed before they return to the index. Requesting indexing in URL Inspection for key pages, listing them in the sitemap with an accurate lastmod date and linking to them from the language switcher all help Google find the changes sooner.
The Hreflang Checker follows each cluster of locale pages and validates return tags, language codes, x-default, sitemap consistency, target reachability and canonical alignment, so pages whose canonical disagrees with the cluster are listed with the fix.
Open Hreflang Fixes โ