Index of every page on this site: llms.txt

Canonical URLs in Vue

Add canonical URLs in Vue with @unhead/vue and Vue Router to declare a preferred URL for duplicate pages. Test declared and Google-selected canonicals.
Harlan Wilton10 mins read Published Updated
What you'll learn
  • Vue Router doesn't set canonicals automatically; use @unhead/vue to add them per route
  • Canonical tags are hints, not directives: Google may choose a different canonical
  • Always use absolute URLs (https://mysite.com/page, not /page)
  • Self-referencing canonicals are recommended even for unique pages

In plain Vue, choose your canonical preferences and implement them with @unhead/vue and Vue Router. Nuxt can generate canonicals from site config when you configure the relevant SEO module. Google does not require a canonical declaration on every page.

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

Quick Setup

Add canonical URLs to your Vue pages using Unhead composables:

Basic Usage
<script setup lang="ts">
import { useHead } from '@unhead/vue'

useHead({
  link: [
    {
      rel: 'canonical',
      href: 'https://mysite.com/products/phone'
    }
  ]
})
</script>
With Query Params
<script setup lang="ts">
import { useHead } from '@unhead/vue'

const sort = 'price'

// Keep sort parameter in canonical
useHead({
  link: [
    {
      rel: 'canonical',
      href: `https://mysite.com/products?sort=${sort}`
    }
  ]
})
</script>
Cross Domain
<script setup lang="ts">
import { useHead } from '@unhead/vue'

useHead({
  link: [
    {
      rel: 'canonical',
      href: 'https://otherdomain.com/original-article'
    }
  ]
})
</script>

For Vue applications, you'll need to install Unhead manually.

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 does not require any canonicalization method, and a site can rank fine without specifying a preference at all. Google weighs your signal alongside other factors when it decides which URL to show in 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.

Important Notes

Google recommends self-referencing canonicals even for pages with a single, unique source of content: they establish a clear preferred URL and prevent search engines from guessing when tracking parameters or alternate URL formats appear.

  • Use absolute URLs, as Google recommends (Google documentation)
  • Keep one consistent canonical declaration. Conflicting declarations can be ignored
  • Prefer initial HTML for clear canonical declarations. Google also supports JavaScript-injected canonicals when rendering succeeds
  • Include canonical pages in sitemaps, exclude non-canonical pages
  • Don't combine a canonical with noindex meta robots: they send conflicting signals
Canonicals only work when the target page has substantially similar content to the source. Pointing a canonical at a different page or your homepage doesn't consolidate rankings; Google is likely to ignore it.

Common Patterns

Filter and Sort Parameters

pages/products/[category].vue
<script setup lang="ts">
import { useHead } from '@unhead/vue'
import { useRoute } from 'vue-router'

const route = useRoute()

useHead({
  link: [{
    rel: 'canonical',
    // Consolidate substantially duplicate sort and filter variants.
    // Keep pagination when it represents different content.
    href: () => {
      const url = new URL(route.path, 'https://mysite.com')
      const page = route.query.page
      if (typeof page === 'string')
        url.searchParams.set('page', page)
      return url.href
    }
  }]
})
</script>

Paginated pages need their own self-referencing canonicals too. Don't point them all to page 1: each page in the sequence has unique content and should be indexed separately. See the Pagination SEO guide for implementation details.

Mobile/Desktop Versions

If you serve separate mobile URLs (m.domain.com), the desktop URL is always the canonical: point rel=canonical on the mobile page to the desktop URL, and rel=alternate on the desktop page to the mobile URL.

pages/products/[id].vue
<script setup lang="ts">
import { useHead } from '@unhead/vue'
import { useRoute } from 'vue-router'

const route = useRoute()

useHead({
  link: [{
    rel: 'canonical',
    // Mobile site (m.mysite.com) points to desktop
    href: () => new URL(route.path, 'https://mysite.com').href
  }]
})
</script>

Responsive design with a single URL avoids needing this canonical/alternate pairing at all, and is what Google recommends for new sites.

Cross-Domain Syndication

Google advises syndication partners to block indexing when you want their copies excluded from Search. Canonicals are not recommended for this purpose because the pages can differ. Apply noindex only to the partner's copy. Keep the original indexable.

Partner site: pages/syndicated-copy.vue
<script setup lang="ts">
import { useSeoMeta } from '@unhead/vue'

// Runs on the partner copy only, never on your original article.
useSeoMeta({
  robots: 'noindex, follow'
})
</script>
pages/original-article.vue
<script setup lang="ts">
import { useHead } from '@unhead/vue'

// If this IS the original, use self-referencing canonical
useHead({
  link: [{
    rel: 'canonical',
    href: 'https://mysite.com/articles/original-slug'
  }]
})
</script>

Testing

Use Google Search Console's URL Inspection tool to compare your declared canonical with Google's selected canonical. For a full detection workflow, see Duplicate Content.

  • 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

Record the canonical edit date beside Google's last crawl and selected canonical. Reported internal observations put typical canonical changes at 1 to 3 weeks, with months for conflicting signals.

Check live declarations, redirects, links, and sitemap URLs for consistency. These processing times are context, not a deadline for Google to accept your preference.

Handling Edge Cases

Multiple Language Versions

For multilingual sites, combine canonicals with hreflang. This partial excerpt shows an English canonical and one alternate. Each localized page needs a self-reference and matching return links; follow Google's localization guide.

<script setup lang="ts">
import { useHead } from '@unhead/vue'

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

Protocol/WWW Variations

Handle protocol and host variants through server redirects. Use a configured public origin. Never construct a redirect destination from an untrusted Host header. Configure proxy trust for the actual deployment topology.

Dynamic Canonicals

For dynamic routes, ensure canonical URLs are consistent:

composables/useCanonical.ts
export function getCanonical(path: string) {
  const siteUrl = import.meta.env.VITE_SITE_URL
  return {
    link: [{
      rel: 'canonical',
      href: `${siteUrl}${path}`
    }]
  }
}

Checklist

Checklist
  • Canonical preferences are consistent across tags, internal links, redirects, and sitemaps
  • Canonical URLs are absolute as recommended; Google supports relative paths but warns about deployment mistakes
  • Only one canonical tag exists per page
  • Canonicals are available in the initial HTML where practical, and rendered tags are verified
  • Paginated pages each get their own canonical, not all pointing to page 1
  • Canonical and noindex are never combined on the same page

If you're using Nuxt, check out Nuxt SEO which handles much of this automatically: canonical URLs in Nuxt →

Was this page helpful?