Skip to content
duxt

SEO

What every page emits for crawlers and social cards, which module writes it, and the one value the layer cannot guess.

Every page emits a full head, a structured description of itself, a social card and an entry in the sitemap. Most of it is written by Nuxt SEO, which the layer installs as one bundle; the rest is the part that depends on versions and translations, and that is the layer's own. One value has to come from you.

Per page

  • Meta — the title with the site name appended, the description, and the og:/twitter: pair derived from both. og:type and og:url are set per page; og:locale and its alternates come from the locales the site serves.
  • JSON-LD — one graph per page: a WebSite (and your Organization, once set) declared site-wide, plus a TechArticle and a BreadcrumbList built from the same trail the breadcrumb draws.
  • An Open Graph image, rendered from the layer's own template — on the landing page too. Ship a component of the same name to replace it.
  • canonical and robots, which are the version half — see URLs and versions. The canonical of an old version points at the current one, which is why the layer writes it rather than letting the module's automatic one stand.

The error page is noindex, follow: a 404 that gets indexed competes with the page the reader was looking for, and the suggestions on it are real pages a crawler should still reach.

Site-wide

/sitemap.xml lists the pages of the default version, per locale. A non-default version is excluded because its pages carry noindex anyway, and an eol version is excluded whether or not it is the default: listing either asks a crawler to fetch exactly what the page then tells it to drop. /robots.txt is generated beside it.

duxt.organization is what names the publisher — see Configuration. Unset, the site still describes itself as a WebSite; what it loses is the entity behind it, which is what a knowledge panel or an AI summary reads to credit a source.

What is checked, and what is only reported

pnpm check:seo reads the built pages and fails over a second canonical, a missing hreflang, an indexable error page, an og:locale in the wrong format, or a graph that does not parse. It runs in pnpm check after the build, because these tags exist only in rendered HTML.

The link checker reports rather than fails. A link pointing nowhere already fails the build through the layer's own build checks, which are the ones that understand versions and locale fallbacks; the module's value here is the devtools panel and the live check while writing.

The one value you must state

The origin. hreflang, canonical, the sitemap and the Open Graph images are all absolute URLs, and a layer cannot know the domain it will be deployed to. Set i18n.baseUrl or NUXT_PUBLIC_I18N_BASE_URL; the layer copies it to site.url, where the SEO modules look.

Left unset, each of them degrades to relative output rather than inventing a domain. That is the deliberate choice: a relative canonical still resolves correctly, and a guessed one is actively wrong — it would point a crawler at somebody else's site.

One more variable for a rolling deploy

NUXT_OG_IMAGE_SECRET signs the Open Graph image URLs. Without it a secret is generated per build, which is fine for one instance and wrong for two: a card whose URL was signed by one instance is rejected by the next, so a link shared during a rolling deploy loses its image. Generate one once — it does not rotate.

Was this page helpful?