> ## Documentation Index
> Fetch the complete documentation index at: https://buttercms.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Structured data & schema markup

> Learn how to add structured data (JSON-LD) to your ButterCMS content for rich snippets in search results.

# Structured data & schema markup

## What is structured data?

Structured data helps search engines understand the content of your pages better. You can add schema markup using [JSON-LD](https://json-ld.org/) by inserting it directly into the page. This lets the markup exist in the HTML sent from the server, which is important for SEO.

{/* SOURCE: file_path="blog-posts/gsd/understanding-content-strategies-through-blog-posts.md" section="Schema markup" */}

Schema markup is a structured data format that helps search engines better understand your website's content. If you are a cooking website, recipe schema can provide additional context to search engines about your recipes.

## Why use structured data?

| Benefit                  | Description                                                    |
| ------------------------ | -------------------------------------------------------------- |
| **Rich Snippets**        | Enhanced search results with ratings, images, prices, and more |
| **Better Understanding** | Helps Google understand your content context                   |
| **Voice Search**         | Structured data powers voice assistant responses               |
| **Knowledge Panels**     | Can contribute to Google's knowledge graph                     |
| **Higher CTR**           | Rich results typically have higher click-through rates         |

## Common schema types

<AccordionGroup>
  <Accordion title="Article Schema">
    Best for blog posts, news articles, and editorial content.

    ```json theme={null}
    {
      "@context": "https://schema.org",
      "@type": "Article",
      "headline": "Article Title",
      "author": { "@type": "Person", "name": "Author Name" },
      "datePublished": "2024-01-15",
      "image": "https://example.com/image.jpg"
    }
    ```
  </Accordion>

  <Accordion title="Organization Schema">
    For company or brand pages.

    ```json theme={null}
    {
      "@context": "https://schema.org",
      "@type": "Organization",
      "name": "Company Name",
      "url": "https://example.com",
      "logo": "https://example.com/logo.png"
    }
    ```
  </Accordion>

  <Accordion title="Product Schema">
    For e-commerce and product pages.

    ```json theme={null}
    {
      "@context": "https://schema.org",
      "@type": "Product",
      "name": "Product Name",
      "image": "https://example.com/product.jpg",
      "offers": {
        "@type": "Offer",
        "price": "99.99",
        "priceCurrency": "USD"
      }
    }
    ```
  </Accordion>

  <Accordion title="FAQ Schema">
    For frequently asked questions pages.

    ```json theme={null}
    {
      "@context": "https://schema.org",
      "@type": "FAQPage",
      "mainEntity": [{
        "@type": "Question",
        "name": "What is ButterCMS?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "ButterCMS is a headless CMS..."
        }
      }]
    }
    ```
  </Accordion>

  <Accordion title="BreadcrumbList Schema">
    For site navigation breadcrumbs.

    ```json theme={null}
    {
      "@context": "https://schema.org",
      "@type": "BreadcrumbList",
      "itemListElement": [{
        "@type": "ListItem",
        "position": 1,
        "name": "Home",
        "item": "https://example.com/"
      }]
    }
    ```
  </Accordion>
</AccordionGroup>

## Implementing schema in Angular

In Angular, you can add schema markup using JSON-LD by inserting it directly into the page with Renderer2:

```typescript theme={null}
import { Component, OnInit, Renderer2, ElementRef } from '@angular/core';

@Component({
  selector: 'app-article',
  templateUrl: './article.component.html',
})
export class ArticleComponent implements OnInit {
  constructor(private renderer: Renderer2, private el: ElementRef) {}

  ngOnInit() {
    const schema = {
      "@context": "https://schema.org",
      "@type": "Article",
      "headline": "Angular SEO Guide",
      "author": {
        "@type": "Person",
        "name": "Your Name"
      },
      "datePublished": "2025-08-06"
    };

    const script = this.renderer.createElement('script');
    script.type = 'application/ld+json';
    script.text = JSON.stringify(schema);
    this.renderer.appendChild(this.el.nativeElement, script);
  }
}
```

This code adds schema.org structured data using JSON-LD inside a `<script>` tag. Search engines read this to understand the page content better.

## Implementing schema in React/Next.js

For React and Next.js applications, you can create a reusable component for structured data:

```jsx theme={null}
// components/StructuredData.jsx
import Head from 'next/head';

export function StructuredData({ data }) {
  return (
    <Head>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
      />
    </Head>
  );
}

// Usage in a page component
import { StructuredData } from '../components/StructuredData';

export default function BlogPost({ post }) {
  const articleSchema = {
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": post.seo_title || post.title,
    "author": {
      "@type": "Person",
      "name": `${post.author.first_name} ${post.author.last_name}`
    },
    "datePublished": post.published,
    "dateModified": post.updated,
    "image": post.featured_image,
    "description": post.meta_description
  };

  return (
    <>
      <StructuredData data={articleSchema} />
      {/* Rest of your component */}
    </>
  );
}
```

## Using ButterCMS data for schema

When fetching content from ButterCMS, map your content fields to schema properties:

### Blog Post article schema

```javascript theme={null}
// Fetch blog post from ButterCMS
const response = await butter.post.retrieve('my-post-slug');
const post = response.data.data;

// Create Article schema
const articleSchema = {
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": post.seo_title || post.title,
  "description": post.meta_description || post.summary,
  "image": post.featured_image,
  "author": {
    "@type": "Person",
    "name": `${post.author.first_name} ${post.author.last_name}`,
    "url": `/author/${post.author.slug}`
  },
  "publisher": {
    "@type": "Organization",
    "name": "Your Site Name",
    "logo": {
      "@type": "ImageObject",
      "url": "https://yoursite.com/logo.png"
    }
  },
  "datePublished": post.published,
  "dateModified": post.updated,
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": `https://yoursite.com/blog/${post.slug}`
  }
};
```

### Page schema with SEO Component

```javascript theme={null}
// Fetch page from ButterCMS
const response = await butter.page.retrieve('landing_page', 'my-page-slug');
const page = response.data.data;

// Create WebPage schema using SEO component data
const pageSchema = {
  "@context": "https://schema.org",
  "@type": "WebPage",
  "name": page.fields.seo?.title || page.name,
  "description": page.fields.seo?.description,
  "image": page.fields.seo?.og_image,
  "url": `https://yoursite.com/${page.slug}`,
  "datePublished": page.published,
  "dateModified": page.updated
};
```

### Collection items (e.g., FAQ schema)

```javascript theme={null}
// Fetch FAQ collection from ButterCMS
const response = await butter.content.retrieve(['faq']);
const faqs = response.data.data.faq;

// Create FAQPage schema
const faqSchema = {
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": faqs.map(faq => ({
    "@type": "Question",
    "name": faq.question,
    "acceptedAnswer": {
      "@type": "Answer",
      "text": faq.answer
    }
  }))
};
```

## Creating a schema Component in ButterCMS

You can create a dedicated Structured Data component in ButterCMS to give content editors control over schema markup:

```
Structured Data Component:
├── schema_type (Dropdown: Article, Product, FAQ, Organization, etc.)
├── headline (Short Text)
├── description (Long Text)
├── image (Media)
├── author_name (Short Text)
├── date_published (Date)
├── date_modified (Date)
└── additional_properties (Long Text - JSON format)
```

Then in your frontend:

```javascript theme={null}
function generateSchemaFromComponent(schemaData) {
  const baseSchema = {
    "@context": "https://schema.org",
    "@type": schemaData.schema_type,
    "headline": schemaData.headline,
    "description": schemaData.description,
    "image": schemaData.image,
    "datePublished": schemaData.date_published,
    "dateModified": schemaData.date_modified
  };

  // Add author if provided
  if (schemaData.author_name) {
    baseSchema.author = {
      "@type": "Person",
      "name": schemaData.author_name
    };
  }

  // Merge additional properties if provided
  if (schemaData.additional_properties) {
    try {
      const additionalProps = JSON.parse(schemaData.additional_properties);
      return { ...baseSchema, ...additionalProps };
    } catch (e) {
      console.warn('Invalid JSON in additional_properties');
    }
  }

  return baseSchema;
}
```

## Testing your structured data

<Info>
  Always validate your structured data before deploying to production.
</Info>

### Recommended testing tools

| Tool                     | Purpose                           | URL                                                                                |
| ------------------------ | --------------------------------- | ---------------------------------------------------------------------------------- |
| Google Rich Results Test | Test for rich snippet eligibility | [search.google.com/test/rich-results](https://search.google.com/test/rich-results) |
| Schema Markup Validator  | Validate schema.org syntax        | [validator.schema.org](https://validator.schema.org/)                              |
| Google Search Console    | Monitor schema performance        | [search.google.com/search-console](https://search.google.com/search-console)       |

### Common validation errors

<Warning>
  Watch out for these common structured data errors:

  * Missing required properties (e.g., `image` for Article)
  * Invalid date formats (use ISO 8601: `YYYY-MM-DD`)
  * URLs without proper protocol (`https://`)
  * Invalid JSON syntax
</Warning>
