Harness-engineering nuxt-seo-metadata

Nuxt SEO Metadata

install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/nuxt-seo-metadata" ~/.claude/skills/intense-visions-harness-engineering-nuxt-seo-metadata && rm -rf "$T"
manifest: agents/skills/claude-code/nuxt-seo-metadata/SKILL.md
source content

Nuxt SEO Metadata

Set page titles, Open Graph tags, canonical URLs, and structured data with useSeoMeta and useHead

When to Use

  • You need to set unique
    <title>
    ,
    <meta description>
    , or OG tags per page
  • You are implementing social sharing previews (og:image, twitter:card)
  • You need to configure robots directives or canonical URLs
  • You are adding JSON-LD structured data for search engine rich results
  • You want to set global defaults and override them per page

Instructions

useSeoMeta — typed meta tags (preferred):

  1. Use
    useSeoMeta
    for all standard SEO and OG meta tags. It provides full TypeScript autocompletion and prevents common tag duplication mistakes:
// pages/product/[id].vue
useSeoMeta({
  title: product.name,
  description: product.description,
  ogTitle: product.name,
  ogDescription: product.description,
  ogImage: product.imageUrl,
  ogType: 'product',
  twitterCard: 'summary_large_image',
  twitterTitle: product.name,
  twitterImage: product.imageUrl,
});
  1. Use
    useServerSeoMeta
    in SSR-only contexts for better performance (skips client-side hydration):
useServerSeoMeta({
  robots: 'index, follow',
  ogSiteName: 'My Site',
});

useHead — generic head management:

  1. Use
    useHead
    for tags not covered by
    useSeoMeta
    (canonical, structured data, custom link tags):
useHead({
  link: [{ rel: 'canonical', href: `https://mysite.com${route.path}` }],
  script: [
    {
      type: 'application/ld+json',
      innerHTML: JSON.stringify({
        '@context': 'https://schema.org',
        '@type': 'Product',
        name: product.name,
        offers: { '@type': 'Offer', price: product.price },
      }),
    },
  ],
});
  1. Set global defaults in
    app.vue
    or a layout, then override per page:
// app.vue
useHead({
  titleTemplate: (title) => (title ? `${title} — My Site` : 'My Site'),
  htmlAttrs: { lang: 'en' },
  meta: [{ name: 'theme-color', content: '#ffffff' }],
});

Reactive meta — computed values:

  1. Pass computed refs or reactive values to update meta when data changes:
const { data: post } = await useAsyncData('post', () => fetchPost(id));

useSeoMeta({
  title: () => post.value?.title ?? 'Loading...',
  description: () => post.value?.excerpt,
  ogImage: () => post.value?.coverImage,
});

Robots configuration:

  1. Configure robots globally in
    nuxt.config.ts
    :
export default defineNuxtConfig({
  app: {
    head: {
      meta: [{ name: 'robots', content: 'index, follow' }],
    },
  },
});
  1. Block specific pages from indexing:
// pages/admin/settings.vue
useSeoMeta({ robots: 'noindex, nofollow' });

nuxt-site-config module:

  1. For production-grade SEO including automatic canonical URLs, robots.txt, and sitemap integration, use the
    @nuxtjs/seo
    module family:
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['nuxt-site-config'],
  site: {
    url: 'https://mysite.com',
    name: 'My Site',
    defaultLocale: 'en',
  },
});

Details

useSeoMeta vs. useHead:

useSeoMeta
is a higher-level abstraction built on top of
useHead
. It knows which meta tags belong in
name
vs.
property
attributes, prevents duplicate tags, and offers typed keys. Prefer it for all standard SEO and social meta. Use
useHead
for raw head control (scripts, links, custom attributes).

Tag deduplication:

Nuxt uses

@unhead/vue
under the hood. Tags are deduplicated by key — the most recently called composable wins. This means a page's
useSeoMeta
call overrides the layout's defaults without any explicit merge logic.

Open Graph image requirements:

  • Minimum size: 1200x630px for optimal display
  • Use absolute URLs (include the full
    https://
    origin)
  • For dynamic OG images, consider
    @nuxtjs/og-image
    which generates them at build time or on-demand
// With @nuxtjs/og-image
defineOgImage({
  component: 'MyOgImageTemplate',
  title: post.title,
  description: post.excerpt,
});

Structured data (JSON-LD) patterns:

Common schema types for Nuxt apps:

  • Article
    — blog posts, news
  • Product
    — e-commerce
  • BreadcrumbList
    — navigation path
  • Organization
    — company info in layout
  • FAQPage
    — FAQ sections

Place organization-level JSON-LD in the default layout; page-specific data in individual pages.

Performance note:

useServerSeoMeta
renders meta tags only during SSR and skips the client-side hydration step, reducing JavaScript execution. Use it for any meta that does not need to change after initial render.

Source

https://nuxt.com/docs/getting-started/seo-meta

Process

  1. Read the instructions and examples in this document.
  2. Apply the patterns to your implementation, adapting to your specific context.
  3. Verify your implementation against the details and edge cases listed above.

Harness Integration

  • Type: knowledge — this skill is a reference document, not a procedural workflow.
  • No tools or state — consumed as context by other skills and agents.

Success Criteria

  • The patterns described in this document are applied correctly in the implementation.
  • Edge cases and anti-patterns listed in this document are avoided.