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.
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…' })