Canonical URLs in Nuxt

Canonical URLs tell search engines which version of a page to index when duplicate content exists. Here's how to set them up in Nuxt.
Harlan WiltonHarlan Wilton10 mins read Published Updated
What you'll learn
  • Canonical tags are hints, not directives—Google may choose differently
  • Always use absolute URLs (https://mysite.com/page, not /page)
  • Self-referencing canonicals recommended even for unique pages

Canonical URLs tell search engines which version of a page is the primary copy when duplicate content exists at multiple URLs. 67.6% of websites have duplicate content issues due to poor canonicalization.

Use canonicals for URLs with query parameters (filters, sorting), same content on multiple paths, paginated sequences, and cross-domain syndication. For redirecting users, use HTTP redirects instead. For blocking pages from search, use meta robots with noindex.

SEO Utils v7.0.19
1.5M
119
SEO utilities to improve your Nuxt sites discoverability and shareability.

Quick Setup

Add canonical URLs to your Nuxt pages using useHead():

Basic Usage
useHead({
  link: [
    {
      rel: 'canonical',
      href: 'https://mysite.com/products/phone'
    }
  ]
})
With Query Params
// Keep sort parameter in canonical
useHead({
  link: [
    {
      rel: 'canonical',
      href: `https://mysite.com/products?sort=${sort}`
    }
  ]
})
Cross Domain
useHead({
  link: [
    {
      rel: 'canonical',
      href: 'https://otherdomain.com/original-article'
    }
  ]
})

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">

Canonical Tags Are Hints, Not Directives

Google treats canonicals as strong signals, not mandatory rules. Google's Joachim Kupke: "It's a hint that we honor strongly. We'll take your preference into account, in conjunction with other signals, when calculating the most relevant page to display in search results."

Google may choose a different canonical than you specify when:

  • Content differs significantly between URLs
  • Multiple conflicting canonical declarations exist
  • Google believes a different page is more authoritative

Google uses the canonical page as the main source to evaluate content and quality. Non-canonical URLs may still be crawled but usually won't appear in search results.

Self-Referencing Canonicals

Self-referencing canonicals are recommended even for unique pages. They establish a clear preferred URL and prevent search engines from guessing when tracking parameters or alternate URL formats appear.

Google's John Mueller: "I recommend using a self-referential canonical because it really makes it clear to us which page you want to have indexed, or what the URL should be when it is indexed."

Important Notes

  • Must use absolute URLs (Google documentation)
  • Only one canonical per page (multiple declarations cause Google to ignore all hints)
  • Must be server-side rendered (crawlers don't run JavaScript)
  • Include canonical pages in sitemaps, exclude non-canonical pages
  • Don't combine canonical with noindex meta robots—sends conflicting signals

Common Patterns

Filter and Sort Parameters

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

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

Use self-referencing canonicals on paginated pages—don't point them all to page 1. Each page in the sequence has unique content and should be indexed separately.

pages/blog/[page].vue
const route = useRoute()
const page = route.params.page || '1'

useHead({
  link: [{
    rel: 'canonical',
    // Each page references itself
    href: `https://mysite.com/blog${page === '1' ? '' : `?page=${page}`}`
  }]
})

Google deprecated rel=prev/next in 2019 and now automatically recognizes pagination patterns.

Mobile/Desktop Versions

If you have separate mobile URLs (m.domain.com), keep the desktop URL as canonical even with mobile-first indexing. Google uses canonicals to understand which pages belong together, then internally selects the mobile version for indexing.

pages/products/[id].vue
const route = useRoute()
const id = route.params.id

useHead({
  link: [{
    rel: 'canonical',
    // Mobile site (m.mysite.com) points to desktop
    href: `https://mysite.com/products/${id}`
  }]
})

Don't switch canonicals from desktop to mobile URLs—Google advises against this. Use responsive design with a single URL instead.

Cross-Domain Syndication

Google no longer recommends cross-domain canonicals for syndicated content. Instead, syndication partners should use noindex meta robots to block indexing.

pages/article/[slug].vue
// If syndicating TO other sites, have them use noindex
useSeoMeta({
  robots: 'noindex, follow'
})
pages/original-article.vue
// If this IS the original, use self-referencing canonical
useHead({
  link: [{
    rel: 'canonical',
    href: 'https://mysite.com/articles/original-slug'
  }]
})

Exception: News publishers syndicating to Google News should still use cross-domain canonicals per Google's news publisher guidance.

Testing

Using Google Search Console

Use the URL Inspection tool to verify canonical implementation:

  1. Enter the URL you want to inspect
  2. Check the "Page indexing" section
  3. Compare "User-declared canonical" vs "Google-selected canonical"
  4. If they don't match, Google found conflicting signals

Note: Live tests won't show Google-selected canonical—you'll only see this for already indexed pages.

When Google Selects a Different Canonical

Common reasons Google ignores your canonical preference:

  • Content differs significantly between URLs
  • Canonical URL returns non-200 status code
  • Canonical URL uses HTTP instead of HTTPS
  • Multiple conflicting canonical declarations on page
  • Canonical chain detected (A → B → C)

Fix canonicalization issues by checking internal links, sitemap inclusion, and removing conflicting signals.

Important Checks

  • Validate absolute URL format
  • Check for canonical chains (A → B → C)
  • Verify SSR implementation (view page source, not inspected HTML)
  • Test with and without parameters
  • Don't combine canonical with noindex meta robots

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 in nuxt.config.ts:

nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    // Redirect non-www to www
    'http://mysite.com/**': { redirect: 'https://www.mysite.com/**' }
  }
})

Or handle with Nitro middleware:

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

Dynamic Canonicals

For dynamic routes, create a composable for consistent canonical URLs:

composables/useCanonical.ts
export function useCanonical(path: string) {
  const config = useRuntimeConfig()
  return {
    link: [{
      rel: 'canonical',
      href: `${config.public.siteUrl}${path}`
    }]
  }
}
nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      siteUrl: process.env.NUXT_PUBLIC_SITE_URL || 'https://mysite.com'
    }
  }
})