JSON-LD Structured Data in Nuxt

Learn how to implement Schema.org structured data in Nuxt. Get rich results in Google search with type-safe JSON-LD markup using the Nuxt Schema.org module.
Harlan WiltonHarlan Wilton8 mins read Published Updated
What you'll learn
  • useSchemaOrg() provides type-safe JSON-LD with automatic graph linking
  • Nuxt Schema.org module sets up WebSite and WebPage schemas automatically
  • Rich results aren't guaranteed—test with Google's Rich Results Test

Schema.org structured data helps Google display Rich Results—stars, FAQs, recipes, product prices. Rotten Tomatoes saw a 25% higher click-through rate on pages with structured data compared to pages without.

<!-- JSON-LD structured data in the head -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "JSON-LD Structured Data in Nuxt",
  "author": { "@type": "Person", "name": "Your Name" }
}
</script>

Google recommends JSON-LD as the easiest format to implement and maintain. Common rich result types:

Rich results aren't guaranteed. Content must match the markup and follow Google's structured data guidelines.

Automated Setup with Nuxt Schema.org

The Nuxt Schema.org module handles structured data automatically with zero config:

Schema.org v5.0.10
3.3M
178
The quickest and easiest way to build Schema.org graphs.

Or install the full Nuxt SEO module which includes Schema.org plus sitemaps, robots.txt, and OG images:

Nuxt SEO v3.3.0
2.1M
1.3K
The all-in-one module that brings it all together.

The module sets up base schema (WebSite, WebPage, Organization/Person) automatically and provides type-safe helpers for all common schema types.

Manual Implementation

Nuxt includes Unhead for head management. You can add JSON-LD via useHead(), but useSchemaOrg() from @unhead/schema-org provides type safety and automatic graph linking.

If you're not using the Nuxt Schema.org module, install the Unhead package:

pnpm add -D @unhead/schema-org

See Unhead Schema.org setup for full install instructions.

import { defineArticle, useSchemaOrg } from '@unhead/schema-org/vue'

useSchemaOrg([
  defineArticle({
    headline: 'JSON-LD Structured Data in Nuxt',
    author: { name: 'Your Name' },
    datePublished: new Date(2024, 0, 15),
  })
])

The defineX() helpers align with Google's Structured Data Guidelines and handle boilerplate:

HelperRich Result Type
defineArticle()Article, NewsArticle, BlogPosting
defineBreadcrumb()Breadcrumb navigation
defineQuestion()FAQ pages
defineProduct()Product listings

Reactive Data

useSchemaOrg() accepts refs and computed getters:

const article = ref({
  title: 'My Article',
  description: 'Article description'
})

useSchemaOrg([
  defineArticle({
    headline: () => article.value.title,
    description: () => article.value.description,
  })
])

Site-Wide Setup

Set up base schema in your root component or layout. Child components can add specific types that link to this graph automatically.

app.vue
<script lang="ts" setup>
import { defineOrganization, defineWebPage, defineWebSite, useSchemaOrg } from '@unhead/schema-org/vue'

const route = useRoute()
useHead({
  templateParams: {
    schemaOrg: {
      host: 'https://mysite.com',
      path: route.path,
      inLanguage: 'en',
    }
  }
})

useSchemaOrg([
  defineWebPage(),
  defineWebSite({
    name: 'My Site',
    description: 'What my site does.',
  }),
  // Use defineOrganization for businesses, definePerson for personal sites
  defineOrganization({
    name: 'My Company',
    logo: '/logo.png',
  })
])
</script>

If using the Nuxt Schema.org module, this configuration is handled automatically in nuxt.config.ts:

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['nuxt-schema-org'],
  site: {
    url: 'https://mysite.com',
    name: 'My Site',
  },
  schemaOrg: {
    identity: {
      type: 'Organization',
      name: 'My Company',
      logo: '/logo.png',
    }
  }
})

Blog Article Example

Nuxt's hierarchical head system means you don't need to repeat WebSite and WebPage if they're in the layout:

pages/blog/[slug].vue
<script lang="ts" setup>
import { defineArticle, useSchemaOrg } from '@unhead/schema-org/vue'

const { data: article } = await useFetch(`/api/articles/${route.params.slug}`)

useSchemaOrg([
  defineArticle({
    headline: article.value.title,
    image: article.value.image,
    datePublished: article.value.publishedAt,
    dateModified: article.value.updatedAt,
    author: {
      name: article.value.author.name,
      url: article.value.author.url,
    }
  })
])
</script>

Testing Your Markup

Use Google's Rich Results Test to validate your structured data. Enter your URL or paste the HTML directly. The tool shows which rich results are eligible and flags any errors.

For local development, inspect the <head> to verify the JSON-LD script tag is present and valid JSON.