Installing @nuxtjs/seo gives your Nuxt app a coordinated set of defaults. It does not establish that the production domain, indexing rules, canonical URLs, page metadata or generated assets match what you intended to publish. Check the response a visitor or crawler actually receives, then trace a mismatch to the module responsible.
These 21 checks focus on the Nuxt SEO bundle after installation. They cover shared configuration, page output and deployment behavior, with examples you can adapt to your own routes. For detailed dynamic sitemap troubleshooting, use the separate Nuxt sitemap checks guide.
The examples follow the official documentation checked on November 2, 2026. The published @nuxtjs/seo 6.0.1 package declares Nuxt ^4.6.1 || ^5.0.0; the installation guide directs Nuxt 3 projects to Nuxt SEO v5. Use the documentation for your installed major version. This is a researched configuration audit, not a claim that we tested your application or measured ranking improvements.
1. Confirm the installed version and module ownership
Start with the lockfile and installed dependency tree, rather than a configuration copied from an older tutorial:
npm ls nuxt @nuxtjs/seo @nuxtjs/robots @nuxtjs/sitemap nuxt-seo-utils
Use the equivalent command for your package manager. A successful package installation is different from a compatible production build. The current installation guide specifies the Nuxt and Node requirements, and explains that incompatible pinned module versions can fail the build.
The v6 bundle includes nine modules, including AI Ready and Skew Protection. If you already use the bundle, avoid adding its constituent modules to the modules array again just because a standalone example shows them. Installing an individual module remains appropriate when that is the stack you deliberately chose.
Record the versions used by CI as well as your workstation. The dependency tree, enabled module list and deployment runtime should describe the same supported combination. Resolve a version conflict explicitly; do not upgrade a production app solely to make a checklist example run.
2. Make disabled modules an explicit decision
An absent output can be intentional. A site with a maintained static share image may not need dynamic OG image generation; another project may choose not to expose AI Ready endpoints.
Check the relevant options in nuxt.config.ts, layers and environment-specific configuration. The disabling guide lists keys such as ogImage, schemaOrg, linkChecker, aiReady and skewProtection. Setting a module key to false skips its setup; enabled: false also removes its output through that module's setup path. Disabling the bundle does not remove a module you separately registered yourself.
Make a small inventory with three columns: module, expected output and reason for enabling or disabling it. For example, “OG Image: disabled; page metadata points to editorially maintained images” explains an absent dynamic image endpoint without treating it as a defect.
Keep Site Config available to the modules that depend on it. Every expected route or tag needs an enabled owner, and every deliberately absent feature needs a clear reason. Avoid turning all automatic defaults off to repair one incorrect tag.
3. Set one production site identity
Inspect a page's canonical URL, og:url, site name and structured-data URLs together. If they disagree about the public hostname, fix the shared configuration before adding page-specific overrides.
The module setup guide notes that Site Config v5 stopped inferring site values from package.json or the project directory. A basic single-domain example is:
// nuxt.config.ts: replace every example value for your site.
export default defineNuxtConfig({
modules: ['@nuxtjs/seo'],
site: {
url: 'https://www.example.com',
name: 'Example Guides',
description: 'Practical guides for maintaining a small website.',
defaultLocale: 'en',
},
})
Request headers alone are an unreliable canonical identity: previews, alternate hostnames and proxies can supply a different origin, while build-time rendering has no visitor request. Verify the deployed values rather than assuming the config file was used by CI.
For multilingual or multi-tenant sites, use the integration's documented runtime configuration. Do not force every tenant or locale onto one hostname merely to make the outputs identical. Use the correct identity for that page consistently across its outputs.
4. Separate production and preview indexing policies
Compare the same route on the public domain and preview domain. Read /robots.txt, the HTML robots tag and the X-Robots-Tag response header. A preview restriction accidentally carried into production can affect an entire release.
Nuxt Robots uses the shared environment and indexable configuration. The environment guide documents NUXT_SITE_ENV=staging for a non-production deployment. Setting site.indexable: false blocks crawling in robots.txt and adds noindex, nofollow to page metadata and headers.
That combination has a limitation: a crawler that obeys the disallow rule cannot fetch the page to read its noindex directive. It is not a reliable way to remove already known public URLs from search results. For that task, the crawler needs access to the noindex response.
Treat preview privacy separately. Robots directives are not authentication; confidential previews need access controls. For a static deployment, check the environment used during the build, since a later runtime variable cannot rewrite already generated HTML. Before release, each environment should serve its intended policy, with no blanket production noindex left behind.
5. Verify page-level indexing directives
A production site can contain both public articles and pages that should stay out of search. Write the intended policy for representative routes before inspecting their output.
For example, this rule marks public internal-search result pages as noindex while allowing links to be followed:
// Relevant options in nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/search/**': { robots: 'noindex, follow' },
},
})
Use this only if it matches your search-page policy. Verify that robots.txt still allows the affected URLs to be fetched when a crawler must see noindex. Inspect headers as well as HTML; an unexpected noindex header can survive an apparently correct page template.
The page-indexing documentation distinguishes build-time definePageMeta rules from runtime useRobotsRule decisions. A profile whose visibility comes from fetched data needs the runtime approach; changing router paths at runtime does not update rules extracted at build time.
For pages you want indexed, do not emit noindex in the initial response and expect client JavaScript to remove it later. Google may skip rendering after seeing that directive. Public, noindex and private routes should each follow their intended policy without contradictory outputs.
6. Confirm content is present in the server response
Fetch a real article URL directly, without first opening the homepage. Read the initial HTML for its heading, substantive content and metadata. A successful browser navigation can hide an empty initial response or a route that only works after client-side routing.
For a content page, use the rendering mode and data-fetching approach deliberately. Nuxt's useFetch documentation describes an SSR-friendly composable that transfers fetched data through the Nuxt payload. Fetching essential article data only in onMounted, or setting server: false, changes what can appear in the server response.
Check whether a route rule disables SSR, a client-only wrapper contains the entire article, or a failed content request produces an empty success page. Static output also needs the actual dynamic URL generated or otherwise supported by the host.
Google can render JavaScript, so missing initial content does not by itself prove that a page cannot be indexed. It does identify a dependency worth investigating, particularly for clients that do not render JavaScript. The SSR and client rendering comparison explains that tradeoff. The chosen delivery mode should produce the intended page, including a meaningful failure response when content is unavailable.
7. Replace generic page titles and descriptions
A slug-derived fallback title or site-wide description prevents an empty field, but it does not establish that the metadata describes an individual page well. Compare two articles with different subjects. Each should have a useful title and summary derived from that article's content.
This illustrative page fragment assumes your own endpoint returns a published article with non-empty title and description fields:
// In app/pages/articles/[slug].vue, inside <script setup>.
const route = useRoute()
const { data: article } = await useFetch(() =>
`/api/articles/${encodeURIComponent(String(route.params.slug))}`,
)
useSeoMeta({
title: () => article.value?.title,
description: () => article.value?.description,
ogTitle: () => article.value?.title,
ogDescription: () => article.value?.description,
})
The endpoint is a placeholder, not an API supplied by the SEO module. Your page must also handle missing records and request errors; optional chaining is not that error-handling policy.
Nuxt recommends useSeoMeta for typed metadata. Inspect the final title with any site template applied, so the brand is not appended twice. Distinct pages need accurate metadata instead of identical defaults or a title copied from an unrelated route. Google may still choose another title link or snippet.
8. Keep metadata reactive during route changes
A direct page load and a client-side route transition exercise different paths. Open article A, follow a Nuxt link to article B, then use Back. Check the title, description and social metadata at each step. They should describe the page currently displayed.
For fetched data that changes when the route parameter changes, pass getters rather than a one-time snapshot:
// Reuses the reactive article ref from the previous example.
useSeoMeta({
title: () => article.value?.title,
description: () => article.value?.description,
})
By contrast, title: article.value?.title reads the value at registration time. That can leave stale metadata when a component instance is reused. A reactive fetch URL also matters: updated head getters cannot fix a data request that never loads article B.
Review server-only conditions around head registration. They can be appropriate for genuinely static metadata, but should not enclose values that must change during client navigation. A global non-reactive app.head declaration is not a substitute for route-aware metadata.
Both fresh requests and A-to-B navigation should produce the intended head. If only navigation fails, investigate data reactivity and component reuse before changing the production canonical domain or indexing policy.
9. Give canonical URLs one effective owner
Inspect the complete <head> for the effective canonical, then check whether page code, a layout, another SEO plugin or a host response header supplies a conflicting value. Counting tags alone is insufficient: one surviving tag can still point to the wrong page.
SEO Utils registers its automatic canonical at low priority. The canonical guide documents a page-level replacement through useHead:
// Use only when this page is genuinely equivalent to the target.
useHead({
link: [{
rel: 'canonical',
href: 'https://www.example.com/guides/preferred-page',
}],
})
The example URL must be replaced with your real preferred page. This is an override for a justified exception, not a pattern to paste into every page. If it fails to appear in initial HTML, confirm that the call ran on the server and inspect competing head sources.
Do not disable automaticDefaults globally to solve one exception: that also removes other automatic metadata. Confirm that the declared canonical is correct and remains consistent after hydration. Google treats canonicalization as a preference supported by several signals; a correct tag does not prove Google has selected that URL.
10. Match canonical case and slash rules to real routes
SEO Utils lowercases canonical URLs by default. That is convenient when your real routing policy also uses lowercase paths. It is a problem if /API/Reference exists but /api/reference returns a 404 or different content.
Request the emitted canonical destination directly. Compare its case, trailing slash, final status and content with the page that declared it. Do the same for an internal link and the sitemap entry representing that page.
If case-sensitive paths are intentional, the documented exception is:
// Relevant SEO Utils option in nuxt.config.ts
seo: {
canonicalLowercase: false,
},
This fragment belongs inside your existing configuration object. Separately check Site Config's trailingSlash policy. Neither a lowercased canonical nor a slash preference proves that your host redirects the other URL variant. The optional redirectToCanonicalSiteUrl setting is disabled by default; verify its actual behavior before enabling broad redirects.
Normalized URLs should resolve to the intended public pages, and the site's links should use that same policy. Fix a real routing mismatch rather than making a canonical point at a URL that merely looks cleaner. If two differently cased paths intentionally serve different content, preserve that distinction.
11. Review query parameters and pagination canonicals
Do not assume Nuxt SEO removes every query parameter. The current default canonicalQueryWhitelist retains page, sort, filter, search, q, category and tag. Those defaults need a content decision, not automatic acceptance or blanket deletion.
Use a few real URLs to classify their behavior:
| Illustrative URL | Content effect | Decision to verify |
|---|---|---|
/guides?utm_source=email |
Tracking only | Prefer the equivalent clean guide URL |
/guides?page=2 |
Different list of guides | Preserve a distinct page URL rather than blindly canonicalizing to page 1 |
/products?sort=price |
Reordered inventory | Decide whether it is an equivalent view and align canonical, links and indexing policy |
A custom whitelist replaces the default list, so retain every parameter your approved URL policy needs. If you keep only page, for example, verify that category or search parameters are not essential to a distinct page before dropping them.
Request page 2 directly and inspect the resulting canonical. Do not declare it equivalent to page 1 just because both use the same template. The canonical-tag guide explains the duplicate-content decision. Document a deliberate policy for each content-bearing parameter and confirm that tracking variants do not introduce conflicting preferred URLs.
12. Reconcile sitemap output with page policy
Take one approved public article and one intentionally noindex page. Compare each page's canonical and indexing directives with the sitemap output. This checks whether the modules agree about the same URL, rather than merely confirming that /sitemap.xml exists.
The public article should use its intended production URL consistently. A URL you deliberately excluded from indexing should not be presented as a preferred indexable destination in your submitted inventory. Investigate mismatches between the page rule, sitemap source and deployed output before changing unrelated metadata.
A route pattern such as articles/[slug].vue does not by itself establish the complete published slug inventory. Likewise, removing a URL from a sitemap does not instruct Google to remove it from the index. Sitemap discovery and page indexing controls have different jobs.
Keep the deeper investigation in the existing Nuxt sitemap guide linked above: it covers dynamic sources, build-time versus runtime output, locale membership, caches and XML comparison. Once representative page policies agree with their sitemap treatment, reconcile the full inventory through that dedicated workflow. Do not treat either a valid sitemap or this small sample as proof that every production page is indexed.
13. Verify locale ownership across head tags
Check a page in each published language. Its visible language, <html lang>, title, description, canonical and social locale should describe the same version of the page.
With automatic defaults enabled, SEO Utils derives language from Site Config. If a manual useHead({ htmlAttrs: { lang: 'ja' } }) call does not produce the intended result, inspect site.defaultLocale and the current locale integration rather than adding more competing tags.
The Nuxt SEO i18n guide requires @nuxtjs/i18n v10 or later for the current bundle. It also documents nuxtSiteConfig translations for locale-specific site names and descriptions. An English homepage can therefore have an English site identity while /fr has a French one, without manually rebuilding every default tag.
Inspect the actual strategy, domain configuration and translated paths used by your app. Do not make the French page canonical to the English homepage merely because they share a template. Where your i18n setup emits alternate-language links, verify those URLs too; do not assume installing the bundle supplies every head integration for every routing strategy.
Direct requests and language switching should retain the intended page identity. A locale prefix alone is not evidence that the metadata or content was translated.
14. Replace placeholder structured-data identity
Open the emitted JSON-LD and look for starter-project names, sample domains, missing logos or an identity type that does not describe the publisher. A valid JSON document can still describe the wrong organization.
Nuxt Schema.org provides default WebSite and WebPage nodes. A stable site identity can be configured separately, following the identity documentation:
// Illustrative fragment inside nuxt.config.ts.
schemaOrg: {
identity: {
type: 'Organization',
name: 'Example Guides',
url: 'https://www.example.com',
logo: '/logo.png',
},
},
Replace these values with real, public publisher details. Verify that the logo URL exists and represents that identity. Choose Person when the site represents an individual; choose an appropriate business identity when that is what the site represents. Do not copy a rich example's address, awards, credentials, ratings or social profiles into your own graph.
The root identity and its relationships should describe the actual site and agree with its visible publisher information. Schema vocabulary validation and Google's feature eligibility are separate checks; an Organization node does not guarantee a knowledge panel or another enhanced search appearance.
15. Match page schema to visible content
The default WebPage graph is not a complete description of every article, product or event. Inspect one real page of each type and decide which additional node, if any, accurately represents its visible content.
For an article, compare the emitted headline, author, publication date, modification date and image with the page. The author should be the real credited author; a publication date should come from the content record, not a fresh timestamp on every request. An image field should point to a relevant accessible image, rather than a placeholder added solely to fill a validator warning.
The module exposes useSchemaOrg and supported node helpers, with default graph configuration that can be extended. Check whether your content integration already emits the page entity before adding another manual copy. Two independently generated article nodes can disagree about author, URL or date even when both parse successfully.
Validate the resulting graph's syntax and vocabulary, then consult Google's current requirements for the particular search feature you seek. Keep the page entity accurate, connected to the correct site identity and supported by visible content. Omit unsupported details instead of inventing them; a supported Schema.org type is not a promise of a Google rich result.
16. Fetch the actual social image in production
Find the effective og:image URL in a deployed page, then request that asset separately. Confirm it returns an image rather than an HTML error page, is accessible without your session and displays readable text with the correct page identity.
The current module setup reference explains an important distinction: installing OG Image does not guarantee generated images. A template needs its renderer dependency. With neither a template nor a renderer, image generation can remain off; a production build using a template without its renderer fails. Signed image URLs also require the documented production secret configuration. Keep secret values out of screenshots and reports.
Use the renderer and deployment instructions for your installed version. Do not assume a development-generated image proves that the production platform can render it. If you use static editorial images instead, verify their absolute URLs and metadata ownership just as carefully.
The page's title, description and image should agree, and the asset must actually be fetchable. After correcting an asset or metadata value, distinguish the live response from a social platform's cached preview; a stale unfurl is not necessarily evidence that your latest HTML is wrong.
17. Check what the link checker actually scanned
Read the link-checking report alongside the pages that were inspected. “No issues found” is useful only within that coverage. It does not prove that every CMS-generated URL or production-only route was included.
Nuxt Link Checker provides development and build-time inspections, including broken links, anchors, redirects and URL conventions. Confirm the relevant module is enabled, then examine its report or DevTools results for real navigation and content links.
Use a published article with a known internal link as a traceable sample. Confirm the checker inspected its source page and reported the destination as expected. Then compare the scanned page list with the public content inventory. Investigate missing dynamic sections or excluded pages before treating a clean result as a complete audit.
Check links in the deployed HTML too. A build can be internally consistent while a host redirect, missing static page or changed public path breaks the live destination. Update links that unnecessarily point through old redirect URLs instead of suppressing every redirect warning.
Record both the report's findings and its omissions. Keep warnings about style conventions separate from links that genuinely fail for users; prioritize broken navigation and missing important destinations.
18. Verify redirects and error response codes
Request old, current and nonexistent URLs directly and read the HTTP response. A page that visually says “not found” while returning 200 is different from a real 404.
The current SEO Utils redirects guide supports moved and gone URL entries. A moved entry defaults to 301; gone entries use an explicit error status. Choose destinations that actually replace the old content, rather than sending every deleted article to the homepage.
| Route case | Output to verify |
|---|---|
| Permanently moved article | Intended 301 or 308 and correct final destination |
| Published current article | Successful response with complete current content |
| Missing article | 404, rather than an empty 200 page |
| Intentionally removed content without replacement | Deliberate 404 or 410 policy |
Deployment changes the implementation. The module documents different static-host outputs and limitations; a generic static deployment cannot necessarily reproduce a Nuxt server's redirect handler. Inspect the actual hosted status and location, not just the config object.
Also try client-side navigation to an old path. A catch-all page can intercept it before a server redirect is reached. Verify that direct requests and in-app navigation lead to the intended result, and that current internal links use the replacement URL.
19. Review publicly exposed AI Ready output
Older tutorials may not mention AI Ready, but it is part of the current bundle. Review its public output after a fresh install or major upgrade rather than assuming only sitemap and robots routes were added.
The setup guide documents /llms.txt, Markdown versions of pages and, when prerendering, /llms-full.txt. It also describes publishing Agent Skills from public/skills/<name>/SKILL.md in the project and layers. Skills in the root skills/ directory remain private under that convention.
Check any generated documents against the site's publication policy. Look for preview text, internal instructions, stale page summaries or resources that should require authentication. Do not move an internal skill into the public directory merely to satisfy an AI discoverability checklist.
An API catalog depends on additional configuration; background indexing and cron are off until enabled. Installing the bundle is not evidence that those systems are running. If AI Ready is unnecessary for your project, the documented aiReady: false option removes its output.
Enabled public routes should expose only intended content and describe it accurately. Availability of an AI-readable endpoint is a delivery feature, not evidence that an AI answer engine fetched it, cited the site or improved its visibility.
20. Preserve old assets across deployments
A page opened before a deployment may still reference JavaScript chunks from the previous build. If those files disappear immediately, that existing session can encounter missing chunks even though a fresh page load works.
Skew Protection addresses this deployment transition, but it needs earlier assets to preserve. The current Nuxt SEO setup guide identifies node_modules/.cache/nuxt-seo/skew-protection as its default history location. A clean CI checkout that discards that directory between builds also discards the history the module needs. Persist the documented directory or configure supported storage for your deployment.
Verify the behavior with two consecutive builds in your own release environment: retain an asset URL from build A, deploy build B, then request that older asset and exercise the existing page session. A newly loaded homepage alone does not check this transition.
The bundle sets polling for update detection and disables the version cookie by default; explicit project options can override those defaults. Do not enable unrelated tracking or cookies simply to complete an SEO check.
The intended earlier assets should remain available through the deployment transition, and the old session should behave correctly. This is release reliability for users and resource fetches, not a ranking improvement you can infer from the module being installed.
21. Keep a representative release evidence matrix
Save an expected-versus-observed record for a small set of routes, then expand coverage to the full approved inventory. Include a normal article, a query variant, another locale, a noindex page, an old URL and a missing URL. Add preview and previous-build asset checks where those features apply.
Copy this template into your release notes. Replace examples and fill observed values from the deployment; blank cells are unfinished checks, not passes.
Build/revision:
Environment and public origin:
Checked at (UTC):
Nuxt / Nuxt SEO versions:
| Case / exact URL | Expected status | Expected canonical | Expected robots | Observed output / evidence | Pass? |
|---|---|---|---|---|---|
| Published article | 200 | Self, public origin | No noindex | | |
| Tracking-only variant | 200 | Equivalent clean URL | Matches page policy | | |
| Page 2, if distinct | 200 | Own page-2 URL | Matches page policy | | |
| Translated article | 200 | Correct locale URL | Matches page policy | | |
| Public noindex page | 200 | Deliberate page policy | noindex; fetch allowed | | |
| Moved article | Intended 301/308 | Correct final page | Check destination | | |
| Missing article | 404 | No unrelated target | Error response | | |
To capture the initial response using the curl command-line client:
curl -sS -D headers.txt -o page.html 'https://www.example.com/articles/example'
Inspect redirects separately before following them, so an unexpected first response is not hidden by the final page. Then compare the rendered head after navigation, the actual social image and the relevant sitemap entry. Record a mismatch with its module owner and the exact evidence, rather than changing several defaults at once.
After a fix, recheck the affected cases against the deployed revision. Search Console can show Google's observed rendering and canonical selection, but distinguish its last crawl from your latest live response. Passing this matrix documents your release checks; it does not establish indexing, citation or rankings.