Set meta and canonicals with useSeoMeta
Nuxt 3 resolves head tags per route through useSeoMeta and useHead. Set title, description, og and canonical in the page that owns the route, using an absolute URL built from runtimeConfig.public.siteUrl. Set the same origin in nuxt.config.ts so the sitemap module and prerender steps agree with it.
Why this matters
One composable per route keeps title, description and canonical aligned.
Before you start
- Nuxt 3 project using SSR or prerendering
- A production site URL available in runtime config
How to apply it
Configure the site URL once
Add runtimeConfig.public.siteUrl to nuxt.config.ts, fed by an environment variable such as NUXT_PUBLIC_SITE_URL, so server and client resolve the same absolute origin.
Check: The deployed page exposes the production origin in its canonical href and never localhost.
Call useSeoMeta in the page
Inside script setup compute const url = new URL(useRoute().path, config.public.siteUrl).href, then call useSeoMeta({ title, description, canonical: url, ogUrl: url }) for that route.
Check: curl -s your production domain/pricing | grep -c 'rel="canonical"' returns 1 and the href is the pricing URL.
Remove global canonical tags
Delete rel=canonical from app.vue, layouts and plugins that run on every route. A global tag pins every page to one URL and defeats per-route canonicals.
Check: Two different routes return two different canonical hrefs.
Use a sitemap module with the same origin
Add @nuxtjs/sitemap with siteUrl taken from the same config and exclude noindexed, admin and draft routes through its exclude option so both signals agree.
Check: curl -s your production domain/sitemap.xml returns 200 and lists only indexable routes.
Check the server-rendered HTML
Fetch a page without JavaScript and confirm the head already contains title, description and canonical. Then request validation for a changed page in Search Console.
Check: curl -s your production domain/<path> contains the canonical in the raw HTML, not only after hydration.
Source: seo-mcp playbook · curated entry · report an error
Framework notes
nuxt
`useSeoMeta({ canonical })` in a page's `script setup` emits the tag during SSR; build the value from `useRuntimeConfig().public.siteUrl` plus `useRoute().path`.