SEO & Metadata

useHead, useSeoMeta, definePageMeta

SEO & Metadata

Set title, description, OG tags, canonical, robots, and JSON-LD per page or globally — Nuxt ships first-class composables for every meta tag you need.

4 min read Level 2/5 #nuxt#seo#meta
What you'll learn
  • Use useSeoMeta for title, description, and Open Graph tags
  • Use useHead for arbitrary link, script, and meta tags
  • Apply site-wide defaults in app.vue

Search engines and social platforms read your <head> to decide what to show. Nuxt gives you typed composables — useSeoMeta and useHead — that work on the server, so the tags are present in the initial HTML.

useSeoMeta — The Common Case

useSeoMeta is a typed wrapper that covers 90% of meta needs in one call.

<script setup lang="ts">
useSeoMeta({
  title: 'Home',
  description: 'Welcome to my Nuxt app',
  ogTitle: 'Home',
  ogDescription: 'Welcome to my Nuxt app',
  ogImage: '/og.png',
  twitterCard: 'summary_large_image',
})
</script>

Every key is autocompleted and type-checked. Nuxt expands them into the right <meta property> / <meta name> pairs.

useHead — Anything Else

For <link>, <script>, custom <meta>, or <html> attributes, drop down to useHead.

<script setup lang="ts">
useHead({
  htmlAttrs: { lang: 'en' },
  link: [{ rel: 'canonical', href: 'https://example.com/' }],
  script: [{ type: 'application/ld+json', innerHTML: JSON.stringify({
    '@context': 'https://schema.org',
    '@type': 'Article',
    headline: 'Hello',
  }) }],
})
</script>

Site-Wide Defaults

Put defaults in app.vue so every page inherits them — per-page calls override.

<script setup lang="ts">
useSeoMeta({
  titleTemplate: '%s · MySite',
  ogSiteName: 'MySite',
  twitterSite: '@mysite',
})
</script>

<template>
  <NuxtPage />
</template>

titleTemplate wraps every page title — a page with title: 'About' becomes About · MySite in the browser tab and OG card.

Tip — Reactive Meta

Both composables accept refs and computed values. Update the title when data loads:

const { data: post } = await useFetch(`/api/posts/${slug}`)
useSeoMeta({ title: () => post.value?.title ?? 'Loading…' })
OG Images & Schema →