Canonical vs hreflang
The usual answer is that they do different jobs: one picks a winner among duplicates, the other points at translations. That is correct, and on its own it is what leads people to set the two up independently and then wonder why the wrong language keeps turning up in the results.
They are not independent. Google’s canonicalization documentation has a section saying that being part of an hreflang cluster makes a URL more likely to be chosen as the canonical. Your language annotations are an input to the duplicate decision.
The part everybody agrees on
Briefly, because it is the half already answered well elsewhere.
rel="canonical"
Nominates which of several addresses holding the same content should be the one in the index.
Between duplicates. Same content, different URLs.
hreflang
Says this page has equivalent versions for other languages or regions, and names them.
Between equivalents. Different content, same purpose.
The distinction to hold on to is duplicates versus equivalents. A French page is not a duplicate of the English one, which is why canonicalising it to the English one is not a tidy-up. It is a request to drop it.
Where they actually meet
This is the sentence the comparison articles leave out. It sits under a heading in Google’s canonicalization documentation called “Prefer URLs in hreflang clusters”:
To help with sites’ localization efforts, for canonicalization purposes Google prefers URLs that are part of hreflang clusters.
Read it as a direction of influence. hreflang does not merely describe your language versions to Google; it changes which address Google prefers when deciding what to keep. The documentation gives a worked example where two regional pages that name each other are preferred as canonicals over a third that is missing from the cluster.
So a page left out of its own hreflang set has not merely lost a translation hint. It has become the weaker candidate in a decision about which version survives.
The mistake this causes
Somebody reads that a canonical consolidates duplicates, decides the language versions are near enough to duplicates, and points all of them at one. Google addresses this directly, on the same documentation page:
If you’re using hreflang elements, make sure to specify a canonical page in the same language, or the best possible substitute language if a canonical page doesn’t exist for the same language.
In practice that means each language version canonicals to itself, which Google recommends generally in any case: Do include a rel="canonical" link on the canonical page itself (also known as a self-referential canonical).
And the set has to include the page it is on. The hreflang documentation is explicit, in a sentence whose middle three words are the ones people drop:
Each language version must list itself as well as all other language versions.
The canonical that is silently ignored
There is a way to write a canonical that Google does not read for canonicalization at all, and nothing flags it, because it is perfectly valid HTML:
rel="canonical" annotations that suggest alternate versions of a page are ignored; specifically, rel="canonical" annotations with hreflang, lang, media, and type attributes are not used for canonicalization.
Worth knowing precisely because it looks deliberate. A canonical carrying an hreflang attribute reads like somebody who understood both mechanisms and combined them. It does nothing, and the page it was meant to consolidate is being judged as though no canonical were there at all.
The relieving one, for anybody who has just discovered their annotations are not a perfect matrix: If it becomes difficult to maintain a complete set of bidirectional links for every language, you can omit some languages on some pages; Google will still process the ones that point to each other.
What to check, in order
The order matters because the first item can make the rest pointless: annotations describing a set you have asked Google to discard are working correctly and achieving nothing.
- 1Check what each language version canonicals to. It should be ITSELF. If every version points at the English one, you have asked Google to keep only the English one, and your hreflang annotations are describing a set whose members you have nominated for removal.
- 2Check that the hreflang list on each page includes that page. A set where every member names the others but not itself is the commonest way these annotations are wasted, and the easiest to see once you know to look.
- 3Check the annotations point both ways. Two pages that name each other are processed; a page naming another that does not name it back is not. You do not need a perfect matrix, which is the part that panics people into rebuilding everything.
- 4Look for a canonical carrying an hreflang, lang, media or type attribute. Those are not read for canonicalization at all, so a canonical written that way does nothing while looking correct in the HTML.
- 5Only then look at which URL Google actually chose, in the URL Inspection tool. A canonical is a strong signal rather than an instruction, and cluster membership is another signal on the same decision, so what matters is what Google picked and not what you asked for.
What this product records about it
ShownTrue reads the canonical on every page it crawls and keeps what it found, including the case above: a canonical that is present, valid, and not eligible to be used. A record of what each page claimed is what lets a later change be compared against something.
It does not manage hreflang, and there is no roadmap on this page pretending otherwise. This guide exists because the canonical half is something a crawler can see, and because the interaction is the part nobody writes down. The capability pages state exactly what exists and what does not.