<link rel="canonical"> tells search engines which URL is the authoritative version of a piece of content. Without it, Google picks for you based on signals it can see — internal links, sitemaps, redirects — and the result is often a URL with tracking parameters, a paginated variant, or a near-duplicate.
Canonical is a hint, not a directive. Google may still pick a different URL if other signals are stronger. But a missing canonical is the loudest possible signal of indifference, and the cheapest one to fix.
When to add a canonical
Every indexable HTML page. Including the homepage. Including pages that you think have no duplicates — query parameters, mixed-case URLs, trailing slashes, and HTTPS/HTTP variants all create duplicates you may not have noticed.
The default canonical is self-referential: the page’s canonical points to itself, on the preferred protocol, host, and path. No query string unless the query string actually distinguishes the content.
How to detect it
curl -s https://example.com/some/page \
| grep -oE '<link[^>]*rel="canonical"[^>]*>'
If the output is empty, there’s no canonical. If there are multiple matches, you have conflicting canonicals (also a problem).
In Google Search Console: URL Inspection shows “User-declared canonical” (what you said) and “Google-selected canonical” (what Google picked). Divergence means Google overrode you. Missing user-declared means you didn’t declare one.
The fix
Universal HTML
<link rel="canonical" href="https://example.com/some/page" />
Rules:
- Absolute URL, including protocol and host.
- One canonical per page. Multiple
<link rel="canonical">tags confuse the picker. - Inside
<head>, before any<meta>that could be parsed instead. - The canonical URL must return
200— don’t canonicalize to a redirected or 404’d target.
HTTP header alternative (for non-HTML resources)
For PDFs and other non-HTML, set the canonical in the response header:
Link: <https://example.com/whitepaper.pdf>; rel="canonical"
WordPress (Yoast / Rank Math)
Both plugins emit a self-referential canonical automatically. Verify it’s working — disable any caching plugin temporarily and view source on a few key pages.
To override on a specific post: Yoast → Advanced tab → Canonical URL. Rank Math → Advanced → Canonical URL.
If your theme also emits a canonical (some do, in header.php), you’ll get duplicates. Remove the theme’s <link rel="canonical"> and let the plugin handle it.
Shopify
Shopify emits a canonical via the theme. Check theme.liquid:
<link rel="canonical" href="{{ canonical_url }}">
If it’s missing, add the line. Shopify’s canonical_url already strips known tracking params and handles ?variant= correctly for product pages.
Static HTML
Add it to your build template. For multi-page sites, generate the canonical from the page’s URL slug at build time.
Next.js (App Router)
Set canonical via metadata API:
// app/blog/[slug]/page.tsx
export async function generateMetadata({
params,
}: {
params: { slug: string };
}): Promise<Metadata> {
return {
alternates: {
canonical: `https://example.com/blog/${params.slug}`,
},
};
}
For sites with metadataBase set in the root layout, you can use a relative path. Verify the rendered HTML — metadataBase errors silently fall back to localhost during dev.
Server-side header (Nginx / Apache)
For non-HTML assets:
location ~ \.pdf$ {
add_header Link '<https://example.com$request_uri>; rel="canonical"' always;
}
Pitfalls
Don’t canonicalize across substantially different content. A blog post and its category page aren’t duplicates — canonical-ing them together hides the category page from search.
Don’t canonicalize the wrong direction for paginated archives. Page 2 of /blog?page=2 should canonical to itself, not to page 1. Google deprecated rel=next/prev in 2019; canonicalizing all pages to page 1 hides paginated content entirely.
Don’t canonicalize HTTPS pages to HTTP, or with-www to without-www inconsistently. Pick one canonical form for the whole site, enforce it via 301, and emit canonical tags matching it.
Don’t include unused query strings in the canonical. A page rendered at /products/widget?utm_source=email should canonical to /products/widget — strip the tracker.
Don’t canonical to a 404 or to a redirect target. Google ignores both and falls back to picking on its own.
Fix at the edge with Serpwise
When the canonical strategy crosses CMS boundaries — marketing on one stack, store on Shopify, help center on a vendor — the safest place to enforce a single canonical strategy is the edge.
Serpwise can inject <link rel="canonical"> based on URL patterns: strip utm_* params, normalize trailing slashes, force HTTPS-only canonicals, override missing canonicals on entire sections of the site — all without touching origin templates.
See pricing or run a free AI visibility audit.