Nuxt 4 SEO and Meta Tags in 2026: useHead, useSeoMeta and Interview Questions

Master Nuxt 4 SEO with useHead and useSeoMeta composables. Learn type-safe meta tags, performance optimization, AI crawler compatibility, and common interview questions.

Nuxt 4 SEO meta tags with useHead and useSeoMeta composables diagram

Nuxt 4 provides two composables for managing SEO meta tags: useHead for general head elements and useSeoMeta for type-safe SEO metadata. With Nuxt 3 reaching end of life on July 31, 2026, understanding these composables in Nuxt 4.5 is essential for any Vue developer preparing for technical interviews.

Key Difference

useSeoMeta handles SEO-specific tags (title, description, Open Graph, Twitter Cards) with full TypeScript support. useHead manages everything else: scripts, stylesheets, canonical URLs, and custom meta tags. Use both together for complete head management.

useSeoMeta: Type-Safe SEO Metadata in Nuxt 4

The useSeoMeta composable accepts a flat object with over 100 typed properties. This approach eliminates common mistakes like confusing name with property attributes on Open Graph tags.

vue
<!-- pages/product/[id].vue -->
<script setup lang="ts">
const product = await useFetch(`/api/products/${route.params.id}`)

useSeoMeta({
  title: () => product.data.value?.name,
  description: () => product.data.value?.description,
  ogTitle: () => product.data.value?.name,
  ogDescription: () => product.data.value?.description,
  ogImage: () => product.data.value?.imageUrl,
  ogType: 'product',
  twitterCard: 'summary_large_image',
  twitterTitle: () => product.data.value?.name,
  twitterDescription: () => product.data.value?.description,
  twitterImage: () => product.data.value?.imageUrl,
})
</script>

The arrow function syntax () => value creates reactive getters. When product.data changes, the meta tags update automatically. For static pages where SEO tags never change after initial render, this reactivity adds unnecessary overhead.

Server-Only Meta Tags for Better Performance

Search engine crawlers and AI bots like GPTBot and ClaudeBot only read the initial HTML response. They do not execute JavaScript. This means client-side meta tag updates are invisible to them.

vue
<!-- pages/about.vue -->
<script setup lang="ts">
if (import.meta.server) {
  useSeoMeta({
    title: 'About SharpSkill',
    description: 'Technical interview preparation platform for developers',
    ogTitle: 'About SharpSkill',
    ogDescription: 'Technical interview preparation platform for developers',
    ogImage: 'https://sharpskill.dev/og-about.png',
    robots: 'index, follow',
  })
}
</script>

Wrapping useSeoMeta in import.meta.server ensures the composable only runs during SSR. The meta tags appear in the HTML sent to crawlers, but no reactive watchers are created on the client. This reduces bundle size and improves hydration performance.

While useSeoMeta covers SEO metadata, useHead handles everything else: external scripts, stylesheets, canonical URLs, and HTML/body attributes.

vue
<!-- pages/blog/[slug].vue -->
<script setup lang="ts">
const route = useRoute()
const config = useRuntimeConfig()

useHead({
  link: [
    {
      rel: 'canonical',
      href: `${config.public.siteUrl}/blog/${route.params.slug}`,
    },
    {
      rel: 'alternate',
      hreflang: 'fr',
      href: `${config.public.siteUrl}/fr/blog/${route.params.slug}`,
    },
  ],
  script: [
    {
      type: 'application/ld+json',
      innerHTML: JSON.stringify({
        '@context': 'https://schema.org',
        '@type': 'Article',
        headline: article.value?.title,
        author: { '@type': 'Person', name: 'Anthony Fillion-Maillet' },
        datePublished: article.value?.publishedAt,
      }),
    },
  ],
})
</script>

The link array handles canonical URLs and hreflang tags for internationalization. The script array injects structured data for rich search results. Both are critical for SEO but fall outside the scope of useSeoMeta.

Ready to ace your Vue.js / Nuxt.js interviews?

Practice with our interactive simulators, flashcards, and technical tests.

Meta Tag Hierarchy: App, Layout, and Page Levels

Nuxt 4 merges meta tags from three levels: nuxt.config.ts (app-wide defaults), layouts, and pages. Page-level tags override layout-level tags, which override app-level tags.

nuxt.config.tstypescript
export default defineNuxtConfig({
  app: {
    head: {
      titleTemplate: '%s | SharpSkill',
      meta: [
        { charset: 'utf-8' },
        { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      ],
      link: [
        { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
      ],
    },
  },
})
vue
<!-- layouts/default.vue -->
<script setup lang="ts">
useSeoMeta({
  ogSiteName: 'SharpSkill',
  twitterSite: '@sharpskill',
})
</script>
vue
<!-- pages/index.vue -->
<script setup lang="ts">
useSeoMeta({
  title: 'Technical Interview Preparation',
  description: 'Prepare for your next technical interview with practice questions and mock interviews',
})
</script>

The final rendered title becomes "Technical Interview Preparation | SharpSkill" because the page provides the %s placeholder value and the config provides the template. This hierarchy avoids repetition while allowing page-specific overrides.

Common Nuxt SEO Interview Questions

Technical interviews for Vue/Nuxt positions often include questions about SSR and SEO optimization. Here are the patterns interviewers expect.

When should useSeoMeta use reactive getters versus static values?

Static values work for pages with fixed content: landing pages, about pages, legal pages. Reactive getters are necessary when meta tags depend on fetched data or route parameters. The performance difference matters at scale: 50 pages with unnecessary watchers waste memory and slow hydration.

How do AI crawlers differ from Googlebot?

Googlebot executes JavaScript and waits for client-side rendering. AI crawlers like GPTBot and ClaudeBot fetch raw HTML without executing scripts. Server-rendered meta tags reach both. Client-only meta tags reach neither AI bot nor older search engines.

What breaks Open Graph tags most often?

Missing og:image dimensions. Facebook and LinkedIn cache OG data aggressively. When the image dimensions are missing, platforms may display thumbnails incorrectly or not at all.

vue
<script setup lang="ts">
useSeoMeta({
  ogImage: 'https://example.com/og-image.png',
  ogImageWidth: 1200,
  ogImageHeight: 630,
  ogImageAlt: 'Article preview showing code editor with Vue syntax',
})
</script>

Including ogImageWidth, ogImageHeight, and ogImageAlt prevents rendering issues and improves accessibility scores.

useHeadSafe for User-Generated Content

When meta tags include user input, XSS vulnerabilities become a concern. The useHeadSafe composable sanitizes values before injection.

vue
<!-- pages/profile/[username].vue -->
<script setup lang="ts">
const user = await useFetch(`/api/users/${route.params.username}`)

useHeadSafe({
  title: user.data.value?.displayName,
  meta: [
    { name: 'description', content: user.data.value?.bio },
  ],
})
</script>

A malicious username like <script>alert('xss')</script> gets escaped rather than executed. Standard useHead does not sanitize, so useHeadSafe is mandatory for any untrusted content.

Nuxt SEO Module for Advanced Requirements

The Nuxt SEO module bundles sitemap generation, robots.txt management, schema.org markup, and OG image generation. For projects requiring comprehensive SEO tooling beyond the built-in composables, this module reduces boilerplate.

nuxt.config.tstypescript
export default defineNuxtConfig({
  modules: ['@nuxtjs/seo'],
  site: {
    url: 'https://sharpskill.dev',
    name: 'SharpSkill',
  },
})

The module auto-generates sitemaps from routes, handles trailing slash normalization, and provides composables for structured data. Teams maintaining large sites benefit from the centralized configuration.

Start practicing!

Test your knowledge with our interview simulators and technical tests.

Nuxt 4 SEO Best Practices for Production

  • Use useSeoMeta for all SEO tags (title, description, Open Graph, Twitter Cards) with TypeScript autocompletion
  • Use useHead for canonical URLs, hreflang tags, structured data, and external scripts
  • Wrap static meta tags in import.meta.server to eliminate client-side reactivity overhead
  • Include ogImageWidth, ogImageHeight, and ogImageAlt for social sharing previews
  • Use useHeadSafe for any user-generated content to prevent XSS attacks
  • Set app-level defaults in nuxt.config.ts and override at page level only when needed
  • Test with Google Rich Results Test to validate structured data
  • Verify rendering in browser DevTools Network tab with JavaScript disabled to simulate crawler behavior
Daily challenge

Can you spot the bug in Vue.js / Nuxt.js?

One real snippet, one hidden bug, one attempt a day. No account needed to try.

Anthony Fillion-Maillet

Written by

Anthony Fillion-Maillet

Founder of SharpSkill

Full-stack developer for over 10 years. Runs SharpSkill and answers for everything published here.

Updated on September 12, 2026

Tags

#nuxt
#seo
#vue
#typescript
#meta-tags

Share

Related articles