Usage

How to use the composable functions of the Nuxt AEO module

The Nuxt AEO module provides two main composable functions:

  • useSchemaFaq(): A helper function for easily adding FAQPage Schema
  • useSchema(): A universal function for adding any Schema type

useSchemaFaq

A dedicated composable for adding question-answer structures to FAQ pages.

URL Normalization

Like useSchema(), useSchemaFaq() also automatically normalizes URLs:

  • Absolute URLs (starting with http:// or https://): Used as-is
  • Relative URLs: Combined with the base URL (from useRequestURL() or app.baseURL)
  • Recursive Processing: URL normalization applies to nested objects and arrays
  • Properties Processed: url, image, logo, and item properties are automatically normalized

Basic Usage

pages/example.vue
<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

Example: FAQ Page

pages/example.vue
<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>

useSchema

A universal composable for adding any Schema type.

URL Normalization

useSchema() automatically normalizes URLs in schema objects:

  • Absolute URLs (starting with http:// or https://): Used as-is
  • Relative URLs: Combined with the base URL (from useRequestURL() or app.baseURL)
  • Recursive Processing: URL normalization applies to nested objects and arrays (e.g., author.url, publisher.logo.url, sameAs[], itemListElement[].item)
  • Properties Processed: url, image, logo, and item properties are automatically normalized

This ensures that all URLs in your schema are absolute URLs, which is required by Schema.org standards.

Basic Usage

Using context and type will automatically convert them to @context and @type internally:

pages/example.vue
<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

Person Schema Example

pages/example.vue
<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>

Organization Schema Example

pages/example.vue
<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>

ItemList Schema Example

pages/example.vue
<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>

Article Schema Example

pages/example.vue
<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>

Automatic Key Conversion

Using context and type in useSchema will automatically convert them to @context and @type internally. This also applies to nested objects:

pages/example.vue
<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:

example.json
{
  "@context": "https://schema.org",
  "@type": "Article",
  "author": {
    "@type": "Person",
    "name": "John Doe"
  }
}

Verification

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):

example.html
<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.


Frequently Asked Questions

This page includes FAQPage Schema to help AI models and search engines understand common questions about using the Nuxt AEO module composables.

pages/example.vue
<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>

Question List

  • What is the difference between useSchemaFaq() and useSchema()?: useSchemaFaq() is a dedicated function for FAQPage with renderHtml default true, while useSchema() is a universal function with renderHtml default false
  • When should I use useSchemaFaq()?: Use it on FAQ pages or pages with question-answer structures
  • Are context and type automatically converted?: Yes, they are automatically converted to @context and @type, and this also applies to nested objects
  • Can I add multiple schemas to one page?: Yes, you can add multiple schemas by calling them multiple times
  • Can I use global schemas and page-specific schemas together?: Yes, both are applied together. Page-specific schemas override global ones for semantic HTML, but both JSON-LD scripts are added
  • How do route-specific schemas work in nuxt.config.ts?: You can configure schemas to be applied only to specific routes by setting the url field. If url is not specified, the schema is applied to all routes

Next Steps