Last Updated
Published

Introduction

Canonical URLs tell search engines which version of a page is the "master" copy when similar content exists at multiple URLs. They're crucial for preventing duplicate content issues and consolidating SEO value.

✅ Good for:

  • URLs with query parameters (e.g., filters, sorting)
  • Same content on multiple paths
  • Mobile/desktop variations
  • Cross-domain syndicated content
  • Paginated content
  • HTTP/HTTPS duplicates

❌ Don't use for:

  • Entirely different content
  • Redirecting users (use HTTP redirects instead)
  • Blocked pages (use meta robots with noindex)
  • Cross-language content (use hreflang instead)

Quick Setup

Add canonical URLs to your Vue pages using Unhead composables:

useHead({
  link: [
    {
      rel: 'canonical',
      href: 'https://mysite.com/products/phone'
    }
  ]
})

Using Nuxt? The Nuxt SEO Utils module can handle this automatically.

Understanding Canonical URLs

A canonical URL is implemented as a link tag in your page's head:

<link rel="canonical" href="https://mysite.com/page">

Key Behaviors

  • Search engines transfer ranking signals to the canonical URL
  • Non-canonical URLs may still be crawled but usually won't be indexed
  • Canonical tags are seen as strong hints, not directives
  • Self-referential canonicals (pointing to the current URL) are valid and recommended

Important Notes

Common Patterns

Filter and Sort Parameters

// pages/products/[category].vue
const { sort, filter, page } = useRoute().query

useHead({
link: [{
rel: 'canonical',
// Only include sort in canonical, remove filter and pagination
href: sort
? `https://mysite.com/products/${category}?sort=${sort}`
: `https://mysite.com/products/${category}`
}]
})

Pagination

// pages/blog/[page].vue
useHead({
  link: [{
    rel: 'canonical',
    // Point all pages to first page
    href: 'https://mysite.com/blog'
  }]
})

For alternative pagination strategies, see Google's pagination guidelines.

Mobile/Desktop Versions

// pages/products/[id].vue
useHead({
  link: [{
    rel: 'canonical',
    // Point mobile site (m.mysite.com) to desktop version
    href: `https://mysite.com/products/${id}`
  }]
})

Consider using responsive design instead of separate mobile sites. See Google's mobile site guidelines.

Cross-Domain Syndication

// pages/article/[slug].vue
useHead({
  link: [{
    rel: 'canonical',
    // Point to original article source
    href: article.originalUrl
  }]
})

Testing

Using Google Search Console

  1. Use URL Inspection tool
  2. Check "Canonical Tag" section
  3. Verify Google's selected canonical
  4. Monitor for canonical conflicts

Important Checks

  • Validate absolute URL format
  • Check for canonical chains (A → B → C)
  • Verify SSR implementation
  • Test with and without parameters
  • Monitor indexing changes
  • Check for conflicting meta robots directives

Handling Edge Cases

Multiple Language Versions

For multilingual sites, combine canonicals with hreflang:

useHead({
  link: [
    {
      rel: 'canonical',
      href: 'https://mysite.com/en/page'
    },
    {
      rel: 'alternate',
      hreflang: 'fr',
      href: 'https://mysite.com/fr/page'
    }
  ]
})

Protocol/WWW Variations

Handle through server redirects rather than canonicals:

// server/middleware/redirects.ts
export default defineEventHandler((event) => {
  const host = getRequestHost(event)
  // Redirect non-www to www
  if (!host.startsWith('www.')) {
    return sendRedirect(event, `https://www.${host}${event.path}`, 301)
  }
})

Dynamic Canonicals

For dynamic routes, ensure canonical URLs are consistent:

// composables/useCanonical.ts
export function useCanonical(path: string) {
  const config = useRuntimeConfig()
  return {
    link: [{
      rel: 'canonical',
      href: `${config.public.siteUrl}${path}`
    }]
  }
}

Core Concepts

Implementation Methods

Additional Resources