Skip to main content
CodeRocket
SEOhightechnical

Set canonical URLs for all pages

rule · canonical-url

Canonical URLs prevent duplicate content issues by specifying the preferred page version. Google's canonicalization guidance (opens in a new tab) works best when URL normalization rules such as lowercase paths and trailing-slash policy already point to the same preferred URL.

Code Example

HTML
<head>
  <link rel="canonical" href="https://example.com/products/widget" />
</head>

Why It Matters

Duplicate content from URL parameters, www vs non-www, or pagination dilutes ranking signals. Canonical tags consolidate those signals to the preferred URL, but they also need to stay consistent with broader canonical-chain cleanup.

When to Use Canonical Tags

ScenarioExampleCanonical To
URL parameters?sort=price&page=1Base URL
HTTP vs HTTPShttp:// and https://HTTPS version
www vs non-wwwBoth existPreferred version
Trailing slash/page and /page/Consistent version
Syndicated contentSame content on multiple sitesOriginal source

Next.js Implementation

TSX
// app/products/[slug]/page.tsx
import { Metadata } from 'next'
 
interface Props {
  params: { slug: string }
}
 
export async function generateMetadata({ params }: Props): Promise<Metadata> {
  return {
    alternates: {
      canonical: `https://example.com/products/${params.slug}`,
    },
  }
}
TSX
// pages/products/[slug].tsx (Pages Router)
import Head from 'next/head'
import { useRouter } from 'next/router'
 
export default function ProductPage() {
  const router = useRouter()
  const canonicalUrl = `https://example.com${router.asPath.split('?')[0]}`
 
  return (
    <Head>
      <link rel="canonical" href={canonicalUrl} />
    </Head>
  )
}

Dynamic Canonical URLs

TSX
// Handle pagination and filters
function getCanonicalUrl(path: string, page?: number): string {
  const baseUrl = 'https://example.com'
 
  // Remove query parameters for canonical-url
  const cleanPath = path.split('?')[0]
 
  // Include page number for paginated content
  if (page && page > 1) {
    return `${baseUrl}${cleanPath}?page=${page}`
  }
 
  return `${baseUrl}${cleanPath}`
}

Common Mistakes

HTML
<!-- ❌ Bad: Relative URL -->
<link rel="canonical" href="/products/widget" />
 
<!-- ✅ Good: Absolute URL -->
<link rel="canonical" href="https://example.com/products/widget" />
 
<!-- ❌ Bad: Wrong protocol -->
<link rel="canonical" href="http://example.com/products/widget" />
 
<!-- ✅ Good: HTTPS protocol -->
<link rel="canonical" href="https://example.com/products/widget" />
 
<!-- ❌ Bad: Includes tracking parameters -->
<link rel="canonical" href="https://example.com/products/widget?utm_source=google" />
 
<!-- ✅ Good: Clean URL -->
<link rel="canonical" href="https://example.com/products/widget" />

Self-Referencing Canonicals

TSX
// Every page should have a canonical-url, even if self-referencing
function PageHead({ path }: { path: string }) {
  const canonicalUrl = `https://example.com${path}`
 
  return (
    <head>
      <link rel="canonical" href={canonicalUrl} />
    </head>
  )
}

Cross-Domain Canonicals

HTML
<!-- When content is syndicated to partner sites -->
<!-- On partner site: -->
<link rel="canonical" href="https://original-site.com/article" />
 
<!-- Original site should NOT link to partner -->

Canonical vs Redirects

Use Canonical WhenUse 301 Redirect When
Same content, different parametersPermanent page move
Content syndicationDomain migration
Print versions of pagesURL structure change
Session IDs in URLsHTTP to HTTPS migration

Exceptions

  • Staging, utility, login, account, or internal search pages may intentionally use different crawl or index signals if they are not meant to rank.
  • Temporary migration states can produce noisy intermediate signals; flag the live production URL pattern, not one-off transition artifacts.
  • When redirects, canonicals, robots directives, or indexability signals conflict, fix the strongest final signal first instead of reporting every downstream symptom as a separate blocker.

Verification

Automated Checks

Manual Checks

  • Verify canonical-url matches preferred URL version