Canonical bugs rarely throw errors. The site renders, the sitemap parses,
search results appear. The damage shows up later as split signals — two
versions of the same page competing for the same query, AI assistants citing
the wrong URL, or Search Console reporting "Google chose different canonical
than user." Google's own
canonicalization docs
are explicit that rel=canonical is a hint, not a directive. Get the hint
wrong and Google picks for you.
This is an inventory. Find the bug you have. Fix it. Move on.
Trailing slash mismatch
The bug: your sitemap lists https://example.com/pricing/ and the canonical
tag on that page says https://example.com/pricing. Google treats these as
two separate URLs. The
2010 Search Central post
on slashes still applies — each URL is evaluated independently.
The cause is usually a templating system that strips slashes for "pretty URLs" while a CMS export keeps them in the sitemap. Or a CDN rewrite rule that adds a slash on edge but the canonical tag is rendered server-side from the un-rewritten path.
Symptom: Search Console shows duplicate URLs flagged as "Alternate page with proper canonical tag" or, worse, "Google chose different canonical than user." The URL you wanted ranking does not rank.
Fix it at the edge. Pick one form. Issue 301 redirects from the other form
to the canonical one. Then make every layer agree — sitemap, internal links,
canonical tag, og:url, structured data url field. A correct setup looks
like this:
<!-- WRONG: tag and sitemap disagree -->
<link rel="canonical" href="https://example.com/pricing">
<!-- sitemap.xml: <loc>https://example.com/pricing/</loc> -->
<!-- RIGHT: every reference uses the same form -->
<link rel="canonical" href="https://example.com/pricing/">
<!-- sitemap.xml: <loc>https://example.com/pricing/</loc> -->Query parameters bleeding into canonical
The bug: a visitor lands on https://example.com/post?utm_source=newsletter
and your CMS renders the canonical tag as the same URL — parameters and
all. Now every UTM variant is its own indexable page. Click counts split.
Backlink equity splits. The clean URL competes with itself.
John Mueller's guidance
is direct: the canonical should point to the clean URL stripped of tracking
parameters. UTM, gclid, fbclid, ref, session IDs — none of them belong
in the canonical tag.
Symptom: Search Console's coverage report fills with parameter variants of the same page. AI assistants cite the UTM-tagged URL because that's what got shared on social. Internal analytics inflate session counts because a self- link with a UTM creates a phantom new visitor.
Fix: render the canonical from the route, not the request URL. Strip the search component before output.
<!-- WRONG: parameters survive into the canonical -->
<link rel="canonical" href="https://example.com/post?utm_source=newsletter&fbclid=IwAR123">
<!-- RIGHT: clean route only -->
<link rel="canonical" href="https://example.com/post">Never UTM-tag your own internal links. That alone causes most parameter bleed.
www vs non-www, and the redirect-without-canonical trap
The bug: www.example.com 301-redirects to example.com, but the canonical
tag on the apex page reads https://www.example.com/.... The redirect tells
Google one thing, the tag tells it another. Google has to guess.
Worse pattern: both hosts serve content with HTTP 200 and identical canonical tags pointing at themselves. That is a true split. Backlink equity divides between the two hosts and neither version wins.
Pick one host. Apex or www, it does not matter — the
Search Central blog
is neutral on which. What matters is that the other host returns a 301 to
the chosen one, and that every canonical, every sitemap entry, every
og:url, and every internal link uses the chosen host.
Verify by curling both hosts. If curl -I https://www.example.com/ returns
200 instead of 301, you have a split. If it returns 301 but the canonical
tag at the destination still references www., your tag is lying.
Mixed http and https in canonical or sitemap
The bug: HTTPS rolled out years ago, but a sitemap generator still emits
http:// URLs, or a hard-coded canonical tag in a legacy template points
to the insecure scheme. Google
prefers HTTPS as canonical
and will usually override the wrong scheme — usually is not always.
The HSTS interaction makes this worse. If your origin sends
Strict-Transport-Security: max-age=31536000, browsers refuse to load
http:// for a year. A canonical tag pointing to http://example.com/page
is a tag pointing at a URL no real browser will ever fetch. AI crawlers
without HSTS state may follow it and get a 301 you did not anticipate.
Symptom: GSC reports the canonical as the HTTPS URL, but inspection shows
the page tag says HTTP. Mixed-content warnings on subresources. Some AI
agents cite an http:// version that immediately redirects.
Fix: grep your codebase for http://yourdomain and replace every match.
Regenerate the sitemap. Add a build-time check that fails CI if any
canonical or sitemap entry uses http://.
Self-referencing canonicals on paginated pages
The bug: /blog?page=2 carries <link rel="canonical" href="https://example.com/blog?page=2">.
That is correct. The mistake is the opposite — pointing page 2's canonical
to /blog (page 1). John Mueller has warned against this for years.
"Page 2 isn't equivalent to page 1," he said in a Search Central hangout —
"the rel=canonical like that would be incorrect."
Google's October 2021 e-commerce documentation made the recommendation
explicit: paginated URLs should be indexable, each with a self-referencing
canonical. The 2019 deprecation of rel=next/rel=prev for indexing did
not change this guidance — it strengthened it.
Why it matters: canonicalizing page 2 to page 1 either gets ignored (because Google sees the pages differ) or gets honored, in which case page 2's unique posts vanish from the index. Either outcome wastes crawl budget.
<!-- WRONG: page 2 claims to be page 1 -->
<!-- on /blog?page=2 -->
<link rel="canonical" href="https://example.com/blog">
<!-- RIGHT: page 2 is its own canonical -->
<!-- on /blog?page=2 -->
<link rel="canonical" href="https://example.com/blog?page=2">The same rule applies to filter URLs that produce genuinely different content. If the filter changes the result set, the filtered URL is its own page and should self-canonicalize.
Cross-domain canonical without a return signal
The bug: you syndicated a post to Medium, used their canonical-import feature to point back to your domain, and then forgot to verify it. Or worse, your CMS canonical-tagged your own post to the syndicated copy. Cross-domain canonicals work — but only when one side points to the other and the target is a real, indexable page.
Symptom: the syndicated copy outranks your original because the canonical chain is broken or reversed. AI assistants cite the third-party domain.
Fix: the original always carries a self-referencing canonical. The
syndicated copy carries <link rel="canonical" href="https://yourdomain.com/post">.
Test by fetching both URLs and reading the head. If the chain is wrong,
the platform either honored a stale tag or the syndication tool never
wrote one.
Verify before shipping
Run isitready.dev on your canonical origin. The audit fetches every page in your sitemap, parses the canonical tag, and flags every mismatch — slash inconsistency, scheme drift, parameter bleed, www splits, paginated misdirection. Each finding includes the raw HTML evidence so you can fix the exact template that emitted it, not guess at which CMS field is wrong.