The Nuxt AEO module provides two main composable functions:
useSchemaFaq(): A helper function for easily adding FAQPage SchemauseSchema(): A universal function for adding any Schema typeA dedicated composable for adding question-answer structures to FAQ pages.
Like useSchema(), useSchemaFaq() also automatically normalizes URLs:
http:// or https://): Used as-isuseRequestURL() or app.baseURL)url, image, logo, and item properties are automatically normalized<script setup lang="ts">
useSchemaFaq({
mainEntity: [
{
name: 'What is the Nuxt AEO module?',
acceptedAnswer: {
text: 'Nuxt AEO is a Nuxt module that supports AI Engine Optimization (AEO) through Schema.org JSON-LD.',
},
},
{
name: 'What Schema types are supported?',
acceptedAnswer: {
text: 'Currently supports Schema types such as Person, FAQPage, ItemList, Article, TechArticle, etc.',
},
},
],
})
</script>
mainEntity (Required)An array of FAQ questions and answers.
Type: Array<{ name: string, acceptedAnswer: { text: string } }>
renderHtml (Optional)Whether to automatically generate semantic HTML.
Type: boolean:brDefault: true
visuallyHidden (Optional)Whether to visually hide the generated HTML.
Type: boolean:brDefault: true
<script setup lang="ts">
const faqs = [
{
question: 'What is the Nuxt AEO module?',
answer: 'Nuxt AEO is a Nuxt module that supports AI Engine Optimization (AEO) through Schema.org JSON-LD.',
},
{
question: 'What Schema types are supported?',
answer: 'Currently supports Schema types such as Person, FAQPage, ItemList, Article, TechArticle, etc.',
},
]
// Add FAQPage Schema
useSchemaFaq({
mainEntity: faqs.map(faq => ({
name: faq.question,
acceptedAnswer: {
text: faq.answer,
},
})),
renderHtml: true, // Generate semantic HTML
visuallyHidden: true, // Visually hide
})
</script>
<template>
<div>
<h1>Frequently Asked Questions</h1>
<div v-for="(faq, index) in faqs" :key="index">
<h2>{{ faq.question }}</h2>
<p>{{ faq.answer }}</p>
</div>
</div>
</template>
A universal composable for adding any Schema type.
useSchema() automatically normalizes URLs in schema objects:
http:// or https://): Used as-isuseRequestURL() or app.baseURL)author.url, publisher.logo.url, sameAs[], itemListElement[].item)url, image, logo, and item properties are automatically normalizedThis ensures that all URLs in your schema are absolute URLs, which is required by Schema.org standards.
Using context and type will automatically convert them to @context and @type internally:
<script setup lang="ts">
// Organization Schema with mixed absolute and relative URLs
useSchema({
context: 'https://schema.org',
type: 'Organization',
name: 'Example Company',
url: '/', // Relative URL - will be normalized to absolute
logo: '/images/logo.png', // Relative URL - will be normalized to absolute
})
// ItemList Schema with mixed absolute and relative URLs
useSchema({
context: 'https://schema.org',
type: 'ItemList',
name: 'Top 10 Programming Languages',
description: 'The most popular programming languages in 2024',
itemListElement: [
{
type: 'ListItem',
position: 1,
name: 'JavaScript',
item: '/tech/javascript', // Relative URL - will be normalized to absolute
},
{
type: 'ListItem',
position: 2,
name: 'Python',
item: 'https://www.python.org', // Absolute URL - used as-is
},
],
})
// Person Schema with mixed absolute and relative URLs
useSchema({
context: 'https://schema.org',
type: 'Person',
name: 'John Doe',
jobTitle: 'Software Engineer',
url: '/profile', // Relative URL - will be normalized to absolute
image: 'https://example.com/profile.jpg', // Absolute URL - used as-is
})
</script>
context (Optional)The Schema.org context URL.
Type: string:brDefault: 'https://schema.org'
type (Required)The Schema type (e.g., 'Person', 'Organization', 'Article', etc.).
Type: string
renderHtml (Optional)Whether to automatically generate semantic HTML.
Type: boolean:brDefault: false
visuallyHidden (Optional)Whether to visually hide the generated HTML.
Type: boolean:brDefault: true
<script setup lang="ts">
useSchema({
context: 'https://schema.org',
type: 'Person',
name: 'John Doe',
alternateName: 'JD',
jobTitle: 'Software Engineer',
url: '/profile', // Relative URL - will be normalized to absolute
image: '/images/profile.jpg', // Relative URL - will be normalized to absolute
knowsAbout: ['JavaScript', 'TypeScript', 'Vue.js'],
sameAs: [
'https://github.com/johndoe', // Absolute URL - used as-is
'/social/twitter', // Relative URL - will be normalized to absolute
],
})
</script>
<script setup lang="ts">
useSchema({
context: 'https://schema.org',
type: 'Organization',
name: 'My Company',
url: '/', // Relative URL - will be normalized to absolute
logo: '/images/logo.png', // Relative URL - will be normalized to absolute
description: 'A great company',
sameAs: [
'https://www.facebook.com/example', // Absolute URL - used as-is
'/social/twitter', // Relative URL - will be normalized to absolute
],
})
</script>
<script setup lang="ts">
useSchema({
context: 'https://schema.org',
type: 'ItemList',
name: 'Top 10 Programming Languages',
description: 'The most popular programming languages in 2024',
itemListElement: [
{
type: 'ListItem',
position: 1,
name: 'JavaScript',
item: '/tech/javascript', // Relative URL - will be normalized to absolute
},
{
type: 'ListItem',
position: 2,
name: 'Python',
item: 'https://www.python.org', // Absolute URL - used as-is
},
{
type: 'ListItem',
position: 3,
name: 'TypeScript',
item: '/tech/typescript', // Relative URL - will be normalized to absolute
},
],
})
</script>
<script setup lang="ts">
useSchema({
context: 'https://schema.org',
type: 'Article',
headline: 'My Article Title',
description: 'Article description',
author: {
type: 'Person',
name: 'John Doe',
url: 'https://example.com/author', // Absolute URL - used as-is
},
datePublished: '2024-01-01',
dateModified: '2024-01-02',
image: '/images/article.jpg', // Relative URL - will be normalized to absolute
publisher: {
type: 'Organization',
name: 'Example Company',
logo: {
type: 'ImageObject',
url: '/logo.png', // Relative URL - will be normalized to absolute
},
},
})
</script>
Using context and type in useSchema will automatically convert them to @context and @type internally. This also applies to nested objects:
<script setup lang="ts">
useSchema({
context: 'https://schema.org', // → "@context": "https://schema.org"
type: 'Article', // → "@type": "Article"
author: {
type: 'Person', // → "@type": "Person" (also converted in nested objects)
name: 'John Doe',
},
})
</script>
Generated JSON-LD:
{
"@context": "https://schema.org",
"@type": "Article",
"author": {
"@type": "Person",
"name": "John Doe"
}
}
Each composable function automatically adds a JSON-LD script tag to the page's <head> tag. You can check this in the Elements tab of Developer Tools (F12):
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Person",
"name": "John Doe",
...
}
</script>
You can also use Google's Rich Results Test to verify that the Schema is correctly recognized.
This page includes FAQPage Schema to help AI models and search engines understand common questions about using the Nuxt AEO module composables.
<script setup lang="ts">
useSchemaFaq({
mainEntity: [
{
name: 'What is the difference between useSchemaFaq() and useSchema()?',
acceptedAnswer: {
text: 'useSchemaFaq() is a dedicated function for easily adding FAQPage Schema, and its renderHtml default value is true. useSchema() is a universal function that can add any Schema type, and its renderHtml default value is false.',
},
},
{
name: 'When should I use useSchemaFaq()?',
acceptedAnswer: {
text: 'It is recommended to use useSchemaFaq() on FAQ pages or pages with question-answer structures. You can easily add FAQPage Schema, and semantic HTML is also automatically generated.',
},
},
{
name: 'Are context and type automatically converted?',
acceptedAnswer: {
text: 'Yes, when you use context and type in useSchema(), they are automatically converted to @context and @type. The type is also automatically converted to @type inside nested objects.',
},
},
{
name: 'Can I add multiple schemas to one page?',
acceptedAnswer: {
text: 'Yes, you can add multiple schemas by calling useSchema() and useSchemaFaq() multiple times. Each call independently generates JSON-LD and adds it to the page.',
},
},
{
name: 'Can I use global schemas and page-specific schemas together?',
acceptedAnswer: {
text: 'Yes, global schemas are automatically injected into all pages, and you can add additional schemas per page using useSchema() or useSchemaFaq(). Both are applied together. When the same schema type is used in both global and page-specific schemas, the page-specific schema will override the global one for semantic HTML, but both JSON-LD scripts will be added.',
},
},
{
name: 'How do route-specific schemas work in nuxt.config.ts?',
acceptedAnswer: {
text: 'You can configure schemas to be applied only to specific routes by setting the url field in the schema configuration. If url is not specified, the schema is applied to all routes. If url is specified, the schema is only applied when the current route path matches exactly. Both relative paths and absolute URLs are supported.',
},
},
],
})
</script>