The Canonical Tag Is a Claim About Identity
By Trent Updated SEO Technical SEO Development 4 min read
A canonical link is one sentence: this URL is the authoritative address for this content. It is not a hint about preference, it is not a redirect, and it is not metadata about the page. It is an identity claim, and identity claims are the kind that fail catastrophically rather than gradually.
The failure that sinks a site
Here is the whole bug, in the form it almost always takes.
A developer adds the canonical tag to a shared layout, because that is where head elements live. The layout needs a value. The obvious value at the time is the site’s own origin, or a prop with a sensible default. It ships.
Every page on the site now says: the authoritative address for this content is the homepage.
The site does not error. Nothing looks wrong. Pages render, links work, the sitemap lists everything, and the analytics keep reporting the same traffic they did yesterday. Then, over the following weeks, the index quietly collapses to one URL — because you told it to, in a machine-readable declaration, on every page.
This is not a hypothetical class of bug. It is the single highest-cost mistake available in a head tag, and it is easy to make precisely because the defaulting behaviour that causes it is the same defaulting behaviour that is correct for every other head element on the page.
Why the default is the problem
Look at what else lives in a layout’s head. A charset. A viewport. A theme colour. A favicon. A font preload. Every one of them is the same on every page, and a shared default is exactly right.
The canonical is the one element in that block that must be different on every page, and it sits among a dozen neighbours where sameness is correct. The habit you build maintaining the rest of the head is the habit that breaks this.
So the fix is not “remember to pass it”. The fix is to make forgetting impossible:
interface Props {
title: string
description: string
/** Path relative to the origin, e.g. "/events". NO DEFAULT, deliberately. */
canonical: string
}
A required prop with no default means the compiler refuses to build a page that does not declare its own identity. The regression stops being discouraged and becomes unrepresentable. That is a meaningfully different guarantee from a comment saying “don’t forget the canonical”.
The three properties worth asserting
Type-checking gets you a value. It does not get you the right value. Three properties are worth checking against the built output, because all three can break while the site continues to look correct:
- Every page declares exactly one canonical. Two is not a stronger claim; it is an ambiguous one, and consumers resolve it by ignoring both.
- Each canonical matches its own path. A page at
/news/fooclaiming/news/baris a page voluntarily deleting itself from the index. This is what catches a copy-pasted template. - No two pages claim the same canonical. This is the original bug, stated as an invariant. If two routes claim one URL, one of them has declared itself a duplicate.
Number three is the important one, and it is the one a per-page test cannot catch. Each page is individually valid; the defect is a property of the set. It only shows up if you collect every canonical in the build and look for collisions — which takes about ten lines and runs in a second.
Trailing slashes are the same bug wearing a different hat
If your canonicals are slashless and your origin serves directory-style URLs, half your pages canonicalise to a URL that 404s. If the reverse, your redirects and your canonicals disagree and every crawl spends two requests where one would do.
There is no correct answer to slash-or-no-slash. There is only consistent, and consistency is not something a convention delivers — the build format, the canonical, the sitemap, the RSS item links and the origin’s own routing all have to agree, and they are configured in four different files by four different people.
So assert it. Walk the output, and fail the build if any canonical, any sitemap entry or any feed link carries a slash the site does not serve. It is a boring check that has never been interesting on the day it passed and would have been extremely interesting on the day it did not.
The underlying idea
A canonical is not an SEO feature bolted onto a page. It is the page asserting what it is, in the one format machines actually read. Treat it as identity — required, unique, verified — and the whole category of index-collapse bugs stops being available to you.
Read next
The whole archive-
SEO
A Taxonomy Is a Commitment, Not a Filing Convenience
Categories, subcategories and tags look like three flavours of the same idea. They are three different promises about permanence, and confusing them is how a site ends up with two answers to what a page is about.
-
SEO
Structured Data Is a Contract, Not a Checkbox
Schema.org markup is usually treated as an SEO garnish you add at the end. It is better understood as a set of machine-readable promises about a page — which means the interesting question is what happens when the page stops keeping them.
-
SecOps
The Dependency You Did Not Choose
Your direct dependencies are a decision. Everything underneath them is a consequence — and on a typical install, the consequences outnumber the decisions by two orders of magnitude.
Keep reading
More on SEO
Every vertical on this site carries its own writing, its upcoming events and its answers on one page — and the whole archive is available as a feed with a real publication date on every item.