Canonical Tags: Why Google Ignores Yours and How to Fix It
You open Google Search Console, go to the Page indexing report, and find pages you care about marked as not indexed: "Duplicate without user-selected canonical", "Alternate page with proper canonical tag", or "Duplicate, Google chose different canonical than user". The names sound alike, the fixes are different, and one of them is not a problem at all.
All three come down to one line of HTML, the canonical tag, and to the fact that Google treats it as a hint rather than an order. This guide covers what a canonical tag is, when you need one, what each Search Console status means and how to fix it, and how to set canonicals correctly on plain HTML, WordPress, Shopify and Next.js.
It is the third part of my SEO checklist series, after page titles and meta descriptions. When I audited a new 22 page blog before launch, missing canonicals were on the list too, and the quickest fix for them in Next.js would have told Google that every page on the site was the home page. The full audit is in the SEO audit checklist.
The short answers
- What is a canonical tag? A line in the
<head>of a page that names the preferred URL for its content:<link rel="canonical" href="https://example.com/page">. - What is it used for? Telling search engines which URL to show when the same or very similar content is reachable at more than one address, so ranking signals collect on one URL instead of being split.
- Does Google have to follow it? No. It is a strong hint. Google weighs it against redirects, internal links, the sitemap and HTTPS, and picks its own canonical when they disagree.
- Should every page have one? Yes. Most pages should point to themselves. This is called a self-referencing canonical.
- Is duplicate content a penalty? No. Google does not penalise ordinary duplicates. It picks one version and leaves the others out, which only hurts when it picks the wrong one.
What a canonical tag is
"Canonical" means the official or standard version of something. In SEO, the canonical URL is the one version of a page that search engines should index and show, out of all the addresses that lead to the same content.
You declare it with one line in the <head>:
<link rel="canonical" href="https://example.com/products/trail-runner">
Visitors never see it. It does not redirect anyone, and every URL keeps working. It only tells search engines which address you consider the main one.
Why one page has many URLs
Most sites have duplicates that nobody created on purpose. The same page can often be reached at:
| Variant | Example |
|---|---|
| HTTP and HTTPS | http://example.com/page and https://example.com/page |
| www and no www | https://www.example.com/page and https://example.com/page |
| Trailing slash | /page and /page/ |
| Tracking parameters | /page?utm_source=newsletter, /page?gclid=... |
| Sorting and filters | /shoes?sort=price, /shoes?color=red |
| Several paths to one item | /collections/sale/products/trail-runner and /products/trail-runner |
| Print, AMP or mobile versions | /page/print, m.example.com/page |
| Capital letters | /Page and /page, on servers that treat them the same |
To a person these are one page. To a crawler they are separate URLs, and each one can collect its own links and its own place in the index.
What a canonical tag does for you
- Picks the URL that appears in search. You decide whether people see
/products/trail-runneror a long collection path with a tracking code on the end. - Combines ranking signals. Links pointing at the duplicates count toward the canonical, instead of being split across versions.
- Saves crawling. Google spends less time on variants and more on your real pages. This matters on large shops and forums; on a 50 page blog it hardly matters.
Canonical URL vs a normal URL
Every page has a URL. The canonical URL is the one chosen, by you or by Google, to represent a group of duplicates. A non-canonical URL is any other address in that group. It still works for visitors; it is just not the one shown in results.
How Google picks the canonical
Google does not take the tag on trust. It groups pages it considers duplicates, then picks one canonical for the group from several signals. Its documentation ranks them roughly like this:
| Signal | Strength | What it means |
|---|---|---|
| 301 or 308 redirect | Strong | The old URL clearly hands over to the new one |
rel="canonical" |
Strong | Your stated preference, in the HTML or an HTTP header |
| Listed in the sitemap | Weak | URLs you submit are treated as preferred |
| Other signals | Varies | HTTPS over HTTP, internal links, links from other sites, shorter and cleaner URLs |
When the signals agree, Google almost always uses your canonical. When they disagree, for example the tag says /page, the sitemap lists /page/ and every internal link goes to /page?ref=nav, Google decides for itself. Most canonical problems are not a missing tag but signals pointing in different directions.
Do you need a canonical tag on every page?
Yes, on every page that can be indexed. Point it at the page's own clean URL:
<!-- On https://example.com/blog/canonical-tags -->
<link rel="canonical" href="https://example.com/blog/canonical-tags">
A self-referencing canonical costs nothing and covers every variant in the table above. If someone shares /blog/canonical-tags?utm_source=reddit, the copy at that address still names the clean URL as the one to index.
Point the canonical at a different URL only when the page really is a duplicate or near duplicate of that URL:
- A product reachable through several category paths points to the main product URL.
- A sorted or filtered listing showing the same items points to the plain listing.
- A print version points to the normal article.
Do not point it at a different page just because the topics overlap. Two articles about running shoes are two pages. If Google sees that the content does not match, it ignores the canonical.
The three canonical statuses in Google Search Console
Open Indexing, then Pages, in Search Console. Under "Why pages aren't indexed" you may see up to three canonical statuses. They are easy to mix up, so here they are side by side:
| Status | What happened | Your canonical | Is it a problem? |
|---|---|---|---|
| Duplicate without user-selected canonical | Google found duplicates and you gave no preference | Missing | Only if Google picked the wrong URL |
| Alternate page with proper canonical tag | The page points to another URL and Google agreed | Present and followed | No, this is the tag working |
| Duplicate, Google chose different canonical than user | The page points somewhere, but Google picked a different URL | Present but overruled | Yes, when Google's choice is the wrong one |
For any URL in these reports, click it and choose Inspect URL. Under Page indexing you will find two lines that answer most questions:
- User-declared canonical: what your tag says.
- Google-selected canonical: what Google actually chose.
If both show the URL you want, there is nothing to fix.
Duplicate without user-selected canonical
Google found two or more URLs with the same content, none of them declared a canonical, and Google picked one itself. The URLs in this report are the ones it did not pick.
The usual causes are the variants in the table above: HTTP and HTTPS both reachable, www and no www both working, URLs with and without a trailing slash, and parameter URLs that Google found through links.
How to fix it:
- Inspect a few URLs from the report and look at the Google-selected canonical. If it is the URL you want indexed, and the reported URL is a variant you do not care about, you can leave it.
- Add a self-referencing canonical to every indexable page, so the choice is yours next time.
- Redirect variants that should not exist with a 301: HTTP to HTTPS, one hostname to the other, one trailing slash style to the other. A redirect is a stronger signal than a tag.
- Link only to canonical URLs, in menus, breadcrumbs, related posts and the sitemap.
- Click Validate fix in the report. Validation can take a few weeks.
If the report lists pages that are not duplicates at all, such as different products, look at the content. Pages with almost no text of their own, like product variants with one word changed or empty category pages, can look like duplicates to Google. Give them real content, or noindex them until they have some.
Alternate page with proper canonical tag
This one is not an error. The page has a canonical pointing at a different URL, Google agreed, and it indexed that other URL instead. Search Console lists the page under "not indexed" because the alternate is, correctly, not in the index.
Typical examples are URLs with tracking parameters, filtered listings, and Shopify product URLs inside a collection path, all pointing to their main version. A large count here is normal for a shop.
It needs attention in only two cases:
- A page you want in search is listed. Its canonical points away by mistake. Inspect it, check the user-declared canonical, and correct the tag or the plugin setting so the page points to itself.
- Alternate URLs are in your sitemap. Filter the report by your submitted sitemap. A sitemap should list only canonical URLs; listing alternates sends Google two different answers.
Duplicate, Google chose different canonical than user
Here you declared a canonical and Google picked another URL anyway. URL Inspection shows the Google-selected canonical, which is the version that is indexed instead.
Sometimes Google is right. If it chose the HTTPS version over an HTTP canonical you forgot to update, fix your tag to match. When it is wrong, the cause is almost always mixed signals:
- Internal links point elsewhere. The tag says
/page, but the menu, breadcrumbs and related posts link to/page/or a URL with parameters. - The sitemap lists a different URL from the one in the tag.
- The canonical URL redirects or fails, so Google cannot use it.
- The canonical URL is
noindex, which tells Google not to index the very page you chose. - The pages are not really duplicates, so Google decides the tag is a mistake and picks the one with more links.
- The pages are too similar to keep apart, like two location pages with the same text and a different city name.
How to fix it:
- Inspect the URL and note both canonicals.
- Decide which one you want. If Google's choice is fine, update your tag, links and sitemap to agree with it.
- If yours should win, make every signal agree. Internal links, sitemap,
hreflangand Open Graph URLs all use the canonical URL, and the canonical answers 200 and is indexable. - If the reported page should not exist on its own, 301 redirect it to the canonical.
- If both pages should rank, make them different. Add content specific to each, and give each a self-referencing canonical.
- Request indexing for the canonical URL and wait for the next crawl.
Mistakes that break canonical tags
Most canonical bugs come from templates, so one mistake usually affects every page at once.
Pointing every page at the home page
This is the one I nearly shipped. A canonical set as a default in a shared layout or theme header, and not overridden on each page, makes every page claim to be the home page. Google usually notices the content does not match and ignores the tags, but at worst it drops pages from the index as duplicates of the home page. The home page itself looks perfect, which is why this goes unnoticed. Check the canonical on a few deep pages, not only the first one.
More than one canonical tag
A theme and an SEO plugin can each add one. If a page has two canonical tags that disagree, Google may ignore both. Keep exactly one.
Relative URLs
<link rel="canonical" href="/page"> is supported, but Google recommends absolute URLs. A relative canonical copied to a staging or mirror domain points at that domain. Use the full URL, with https:// and the right hostname.
A canonical outside the head, or added late by JavaScript
Google only reads rel="canonical" in the <head>. A tag in the body, or broken HTML that closes the <head> early, is ignored. If a script adds or changes the canonical after the page loads, Google may see a different value from the one in the source. Put it in the HTML the server sends.
Canonical and noindex on the same page
noindex says "do not index this page". A canonical to another URL says "index that page instead". Putting both on a duplicate sends a mixed message. Use one: a canonical for duplicates you want combined, noindex for pages you want out of search entirely. Never put noindex on the canonical URL itself.
Pointing paginated pages to page 1
Page 2 of a category lists different items from page 1, so it is not a duplicate. Give each page in the sequence its own self-referencing canonical, and link the pages to each other normally.
A canonical to a URL that redirects or does not exist
A canonical pointing at a 301, a 404 or a page behind a login cannot be used. After moving pages or changing your URL structure, check that canonicals point at the final URL.
Blocking duplicates in robots.txt
If a URL is blocked in robots.txt, Google cannot crawl it, so it never sees the canonical tag on it. Blocked URLs can even be indexed from links alone, without their content. Let Google crawl the duplicates and read the canonical.
How to add a canonical tag
Plain HTML
<head>
<title>Trail Runner - Lightweight Running Shoes for Men</title>
<link rel="canonical" href="https://example.com/products/trail-runner">
</head>
PDFs and other files
Files that are not HTML have no <head>. Google also accepts the canonical as a response header, which is useful when the same PDF lives at two URLs, or when a PDF should point at an HTML page with the same content:
Link: <https://example.com/guides/sizing>; rel="canonical"
WordPress
WordPress adds a self-referencing canonical to posts and pages by itself, and Yoast SEO and Rank Math take over that job when installed. To point a page elsewhere, edit it, open the Advanced section of the plugin's panel and fill in Canonical URL. Leave it empty on normal pages, so the self-referencing default stays.
If a page shows two canonical tags, a theme or a second SEO plugin is adding its own. Keep one source.
Shopify
Shopify themes add the canonical in theme.liquid:
<link rel="canonical" href="{{ canonical_url }}">
Products reached through a collection, like /collections/sale/products/trail-runner, point to /products/trail-runner. That is why Shopify stores show many "Alternate page with proper canonical tag" entries, and why it is safe to leave them. If a page has no canonical at all, check that the line is still in the theme after editing or switching themes.
Next.js (App Router)
Set metadataBase once in the root layout so relative paths become full URLs, then set alternates.canonical on each page:
// app/layout.js
export const metadata = {
metadataBase: new URL('https://example.com'),
}
// app/blog/[slug]/page.js
export const generateMetadata = async ({ params }) => {
const { slug } = await params
const article = await getArticle(slug)
return {
title: article.title,
description: article.excerpt,
alternates: { canonical: `/blog/${slug}` },
}
}
Next.js renders that as <link rel="canonical" href="https://example.com/blog/your-slug">. In Next.js 15 and later params is a promise, hence the await.
Two things to watch:
- Never set
alternates.canonicalin the root layout as a default. Metadata is inherited, so every page that forgets to set its own would point at the home page. This is the mistake from my audit, and it is easy to miss because the home page looks fine. - Match your trailing slash setting. With
trailingSlash: trueinnext.config.js, write canonicals with a trailing slash, or every page points at a URL that redirects.
On a site with many pages, build the canonical in the same function as the rest of the metadata, so it cannot drift away from the Open Graph URL. The one I use is in the audit write-up.
Next.js (Pages Router)
The Pages Router has no Metadata API. Add the tag with next/head, built from the path without its query string:
// pages/_app.js
import Head from 'next/head'
import { useRouter } from 'next/router'
const App = ({ Component, pageProps }) => {
const { asPath } = useRouter()
const path = asPath.split(/[?#]/)[0]
return (
<>
<Head>
<link rel="canonical" href={`https://example.com${path}`} key="canonical" />
</Head>
<Component {...pageProps} />
</>
)
}
export default App
The key lets a single page replace it with its own <link rel="canonical" key="canonical"> when it should point elsewhere. Pages Router pages are rendered on the server, so the tag is in the HTML that Google reads.
Canonicals across domains and languages
A canonical can point to another website. Google supports it, and it is the right tool when you publish the same content on two domains you own.
For articles republished on someone else's site, Google changed its advice in 2023. A cross-domain canonical from the partner's copy is no longer the recommended fix, because Google may still choose the partner's version. Ask partners to add noindex to their copy instead, and to link back to your original.
Translations are not duplicates. Each language version gets its own self-referencing canonical, and hreflang links the versions together. Do not point every translation at the English page, or the other languages drop out of search.
Check every canonical on your site
This script works on any site with a sitemap. It needs Node.js 18 or later, fetches pages one at a time, and lists canonicals that are missing, duplicated, relative, outside the <head>, or pointing at a URL that redirects, fails or is noindex:
// check-canonicals.mjs
// Usage: node check-canonicals.mjs https://example.com
const site = process.argv[2]
const sitemap = await (await fetch(`${site}/sitemap.xml`)).text()
const urls = [...sitemap.matchAll(/<loc>(.*?)<\/loc>/g)].map((m) => m[1].trim().replace(/&/g, '&'))
const canonicalPattern = /<link[^>]+rel=["']canonical["'][^>]*>/gi
const hrefOf = (tag) => (tag.match(/href=(["'])(.*?)\1/i)?.[2] ?? '').replace(/&/g, '&')
const isNoindex = (head) => /<meta[^>]+name=["'](robots|googlebot)["'][^>]*content=["'][^"']*noindex/i.test(head)
const load = async (url) => {
const res = await fetch(url, { redirect: 'manual' })
const html = res.status === 200 ? await res.text() : ''
return { status: res.status, html, head: html.split(/<\/head>/i)[0] }
}
const targets = new Map()
for (const url of urls) {
const page = await load(url)
if (page.status !== 200) {
console.log(`${url}\n answers ${page.status} but is in the sitemap`)
continue
}
const tags = page.head.match(canonicalPattern) ?? []
const outside = (page.html.match(canonicalPattern) ?? []).length - tags.length
const href = tags[0] ? hrefOf(tags[0]) : ''
const problems = []
if (!href) problems.push('no canonical in the head')
if (tags.length > 1) problems.push(`${tags.length} canonical tags`)
if (outside > 0) problems.push('canonical outside the head')
if (isNoindex(page.head)) problems.push('noindex but listed in the sitemap')
if (href) {
if (!/^https?:\/\//i.test(href)) problems.push(`relative canonical: ${href}`)
const canonical = new URL(href, url).href
if (canonical !== new URL(url).href) {
problems.push(`points to ${canonical}`)
if (!targets.has(canonical)) targets.set(canonical, await load(canonical))
const target = targets.get(canonical)
if (target.status !== 200) problems.push(`which answers ${target.status}`)
else if (isNoindex(target.head)) problems.push('which is noindex')
}
}
if (problems.length) console.log(`${url}\n ${problems.join('\n ')}`)
}
It follows the same pattern as the checkers in part 1 and part 2. A sitemap URL whose canonical points somewhere else is not always wrong, but it is always worth a look: either the sitemap or the tag is giving Google the wrong address.
Questions people ask
What is an example of a canonical tag?
<link rel="canonical" href="https://example.com/products/trail-runner">, placed in the <head> of https://example.com/products/trail-runner?color=blue, tells search engines to index the URL without the color parameter.
What does canonical mean in SEO? The preferred version of a page, out of several URLs with the same or very similar content. The canonical URL is the one search engines index and show.
Is a canonical tag the same as a 301 redirect? No. A redirect sends visitors and crawlers to the other URL. A canonical leaves every URL working for visitors and only tells search engines which one to index. Use a redirect when the old URL has no reason to exist, and a canonical when both versions need to work, like filtered listings or tracking links.
How do I fix canonical issues? Inspect the URL in Search Console and compare the user-declared and Google-selected canonicals. Then make your tag, internal links, sitemap and redirects all point at the same URL. The sections above cover each status.
Is duplicate content bad for SEO? Not as a penalty. Google filters duplicates and shows one version. It costs you when Google shows the wrong version, splits links across several URLs, or spends its crawling on copies instead of new pages.
Do canonical tags pass link value? Once Google accepts the canonical, it treats links to the duplicates as signals for the canonical URL, so the value is combined. It is less certain than a redirect, because Google can ignore the tag.
Can I use a canonical tag instead of noindex?
For duplicates, yes, and it is usually better, because the duplicate's links still count toward the main page. Use noindex for pages that should not be in search at all, such as internal search results or thin tag pages.
How long does it take Google to follow a new canonical? Google has to crawl both the duplicate and the canonical again. That can be days for busy pages and weeks for quiet ones. Request indexing for the canonical URL in URL Inspection, then validate the fix in the Page indexing report.
Do other search engines use canonical tags?
Yes. Bing reads rel="canonical" the same way, and also treats it as a hint.
Next in the checklist
This is part 3 of the SEO checklist. Part 1 covers page titles, part 2 covers meta descriptions, and the full list is in the SEO audit checklist. Next come headings: why a page should have exactly one H1, and what happens when it has none.
If you are working through a Search Console report with dozens of URLs, paste the list somewhere you can mark each one as fixed. txtnode opens a notepad at any URL you type, without an account, and Files keeps notes in folders when you sign in.



