Canonical URLs and hreflang: choosing the address search engines show
What a canonical tag tells search engines, the mistakes that make them ignore it, and how hreflang links a page’s language versions.
The same page often loads at several addresses: with tracking parameters such as ?utm_source=newsletter, with a sort order or filter added, or over both http:// and https://. Search engines group the copies and list one of them. A canonical tag tells them which address you’d like that to be.
hreflang does a different job. It links the versions of a page written for different languages or regions, so search can show each person the one that fits.
What SignalDNS checks
We read the canonical links in the page’s head, resolved against the page’s address or its <base>, and a canonical sent in an HTTP Link header, which Google also reads. We compare each with the address the page finally loaded from, after redirects. The scheme, host, path, and query must match exactly; a #fragment is ignored. So https://www.example.com/shoes and https://www.example.com/shoes/ count as different addresses.
For hreflang, we read up to 500 <link rel="alternate" hreflang> links in the head, resolved the same way. We don’t read hreflang from Link headers or sitemaps, and we don’t fetch the other versions.
Both feed “Can search engines list it?”, along with noindex and robots.txt. We read the HTML as the server sends it, before JavaScript runs.
What a canonical tag and hreflang look like
For a page with an English and a German version:
<head>
<link rel="canonical" href="https://www.example.com/en/shoes">
<link rel="alternate" hreflang="en" href="https://www.example.com/en/shoes">
<link rel="alternate" hreflang="de" href="https://www.example.com/de/schuhe">
<link rel="alternate" hreflang="x-default" href="https://www.example.com/shoes">
</head>
- The canonical names the page itself. Its copies, such as
https://www.example.com/en/shoes?utm_source=newsletter, carry the same tag, so they point here. - Each hreflang link names one version, including this one. The German page has the same three hreflang links, and its own canonical,
https://www.example.com/de/schuhe. - Use full addresses, with
https://. Google accepts relative canonicals but recommends against them, and requires full addresses in hreflang.
For a file that isn’t HTML, such as a PDF, send the canonical as a header:
Link: <https://www.example.com/guides/sizing.pdf>; rel="canonical"
The canonical tag doesn’t point to this page
Google treats a canonical as a strong signal, not a rule: it calls it a hint. It weighs it with other signals, such as redirects, sitemaps, and whether a page uses HTTPS, and may choose a different address. Google says these methods stack, so a canonical works best when the other signals agree with it. These are the results we report.
There’s no canonical tag
This is a note, not counted. Google doesn’t require a canonical. Without one, it picks the address to list itself, and Google says a site will likely do fine that way. A canonical helps when copies exist, such as addresses with tracking parameters. Google recommends that the main page carry one pointing at its own address.
The canonical points to this page
The canonical names the address the page loaded from. That’s OK, and it’s what Google recommends for the main version of a page.
The page names more than one canonical
The page names two or more different addresses, from several <link rel="canonical"> tags, or from a tag and a Link header that disagree. Conflicting canonicals don’t state a preference, so search engines are left to choose for themselves. SignalDNS marks this as needing attention.
This can happen when a theme and an SEO plugin both add a tag, or when a server or CDN adds a header the page doesn’t know about.
How to fix it: keep one. Google supports both the tag and the header, but recommends choosing one, since using both makes this mistake easy.
The canonical points to the http:// address
The page loads over https://, but its canonical names the same address with http://. Search engines may list the insecure address instead. SignalDNS marks this as needing attention. One cause is a site address setting left at http:// after a move to HTTPS.
How to fix it: change the canonical to the https:// address, and update the site address in your CMS so new tags use it.
The canonical names another address
The canonical names a different address as the main one, so search engines usually list that one instead. SignalDNS marks this as needing attention, because it’s right for a copy and wrong for an original.
It’s expected on a copy: an address with tracking parameters, a print version, or a sorted list that points to the plain one. It’s a mistake when:
- Every page points to the home page, often from a template that hard-codes the canonical.
- It names a staging or old domain, such as
https://staging.example.com/shoes. - The address differs slightly, by a trailing slash,
www, or a parameter. We compare exactly, so the result shows the address the canonical names. - Language versions all point to one language. Google asks for each version’s canonical to be in that version’s own language.
How to fix it: if this address should be listed itself, point its canonical at itself:
<link rel="canonical" href="https://www.example.com/shoes">
Then use the URL Inspection tool in Search Console to see which address Google chose. Google may still choose another one. Linking to the canonical address throughout your own site helps, Google says.
Language versions leave out this page
hreflang links name each language or regional version of a page. Google asks for every version to list itself and all the others, with the same set of links on each. What we report:
- No hreflang links. A note, not counted. You only need them if the page exists in other languages or for other regions.
- The links include this page. OK, with the number of versions.
- The links leave this page out. The page lists other versions, but none of them is the address it loaded from, and Google’s guidelines say each version must list itself. SignalDNS marks this as needing attention. On a page with 500 or more links we stop reading, so we don’t judge it.
Each pair of pages has to link both ways. If the German page names the English one, the English page must name the German one too; otherwise Google ignores the link. We don’t fetch the other versions, so check those return links yourself.
x-default names the page for anyone whose language you don’t cover, such as a language picker. We don’t count it as a version.
Codes are a language in ISO 639-1, optionally followed by a region in ISO 3166-1 Alpha 2: en, en-GB, de-CH. A region on its own isn’t valid; be is Belarusian, not Belgium. Google doesn’t support codes outside those standards, such as es-419.
How to fix it: put the same links on every version, each naming the exact address that version loads at, and include the page itself:
<link rel="alternate" hreflang="en-GB" href="https://www.example.com/uk/shoes">
<link rel="alternate" hreflang="en-US" href="https://www.example.com/us/shoes">
<link rel="alternate" hreflang="x-default" href="https://www.example.com/shoes">
Point each version’s canonical at itself, not at one main language, since Google asks for a canonical in the page’s own language.
Setting it up in your CMS or framework
- WordPress: rel_canonical(), which adds a canonical to single posts and pages
- Shopify: the canonical_url object, for themes
- Wix: changing the canonical tags for your site’s pages
- Next.js: alternates, for the canonical and hreflang links
- nginx: add_header and Apache: mod_headers, for a canonical
Linkheader on PDFs and other files
What we can’t tell from outside
We read one page. We don’t fetch the canonical address to see whether it loads, or the other language versions to see whether they link back. We read the head before JavaScript runs, so a canonical or hreflang link a script adds isn’t seen; Google advises against using JavaScript to change a canonical the HTML already sets. We don’t read hreflang in sitemaps or headers. And we can’t see which address Google chose: the URL Inspection tool in Search Console shows it.
Sources
- Google: what is URL canonicalization
- Google: how to specify a canonical URL
- Google: fix canonicalization issues
- Google: tell Google about localized versions of your page, for hreflang, return links, codes, and x-default
- Google: understand JavaScript SEO basics, on setting a canonical with JavaScript
- RFC 6596: The Canonical Link Relation
- RFC 8288: Web Linking, for the
Linkheader - Search Console: URL Inspection tool
Last reviewed .