Canonical URLs Explained: Fixing Duplicate Content
A canonical URL tells search engines which version of a page is the main one when the same content is reachable at several addresses — www vs non-www, tracking parameters, sorting options, trailing slashes. How rel=canonical works, how to set it in Next.js, and common mistakes.
The same page on your site can often be reached at several URLs:
https://example.com/pricing
https://www.example.com/pricing
https://example.com/pricing/
https://example.com/pricing?utm_source=newsletter
http://example.com/pricing
To you it's one page. To a search engine it can look like five pages with identical content. That splits signals (links, rankings) between them and leaves the search engine guessing which one to show.
A canonical URL tells search engines: this is the real address of this content.
How to set it
Add a <link> in the page's <head>:
<link rel="canonical" href="https://example.com/pricing" />
Every variant of the page carries the same canonical, pointing to the one preferred URL.
In Next.js (App Router)
// app/pricing/page.tsx
export const metadata = {
alternates: { canonical: 'https://example.com/pricing' },
}
Or set metadataBase in the root layout and use relative paths: alternates: { canonical: '/pricing' }.
Where duplicate URLs come from
- www vs non-www and http vs https (www vs non-www)
- Trailing slashes —
/pricingvs/pricing/ - Tracking parameters —
?utm_source=...,?ref=...(Query parameters explained) - Sorting and filtering —
/shoes?sort=price - Pagination and print versions
- The same article in several categories —
/blog/seo/postand/blog/guides/post - Syndicated content — your article republished on Medium or another site
Canonical vs redirect
| Use | When |
|---|---|
| 301 redirect | Only one version should ever be visited — http→https, www→non-www, old URL→new URL (301 vs 302) |
| Canonical tag | Variants need to keep working for users (tracking links, sorted views) but only one should rank |
Do both where they apply: redirect the host and protocol variants, and use canonicals for parameter variants.
Rules and common mistakes
- Use absolute URLs —
https://example.com/pricing, not/pricingin raw HTML. - Self-referencing canonicals are good practice: each page's canonical points to itself (its clean URL).
- One canonical per page. Two conflicting tags are ignored.
- Don't point every page at the homepage. A canonical must point to a page with the same content.
- Don't canonical paginated pages to page 1 — page 2 has different content.
- Match your sitemap — list only canonical URLs in
sitemap.xml. (robots.txt and sitemap.xml) - Render it on the server. A canonical added by client-side JavaScript may be missed.
Canonicals are a strong hint, not a command. If your internal links, sitemap and redirects all point to a different version, Google may pick that instead. Keep them consistent.
Checking it
- View the page source and search for
canonical. - In Google Search Console, URL Inspection shows the "User-declared canonical" and the "Google-selected canonical". If they differ, something is inconsistent. (Google Search Console for beginners)
Syndication
If your article appears elsewhere, ask the other site to add a canonical pointing to your original — otherwise it may outrank you with your own content.
EasySpawn serves your site from your own server with redirects and server-rendered meta tags under your control, so every page has one clear address. See how it works or join the waitlist.
Related: www vs non-www · 301 vs 302 Redirects · SEO Basics for Your App · Schema Markup Explained
Keep reading
301 vs 302 Redirects (and 307, 308): Which Should You Use?
301 means moved permanently; 302 means temporarily somewhere else. How each affects browsers, caching and SEO, what 307 and 308 add, setting redirects in Nginx, Caddy, Next.js, Express and Cloudflare, and the mistakes that cause redirect loops and lost rankings.
"Your Connection Is Not Private" on Your Own Site: Causes and Fixes
When visitors see NET::ERR_CERT_DATE_INVALID, ERR_CERT_COMMON_NAME_INVALID or ERR_CERT_AUTHORITY_INVALID on your site, the SSL certificate is expired, for the wrong name, or incomplete. How to tell which, and how to fix each one.