Skip to main content
Technology & EngineeringSeo Content232 lines

Structured Data Schema Org

Schema.org structured data markup: JSON-LD implementation for rich results, product/article/FAQ/breadcrumb schemas, validation, and Google Search Console integration.

Quick Summary20 lines
Structured data is the bridge between your page content and search engine understanding. When implemented correctly via JSON-LD, it enables rich results -- star ratings, FAQ accordions, breadcrumb trails, product prices -- that directly increase click-through rates without changing your algorithmic ranking. The ROI of structured data is one of the highest in SEO because the implementation effort is modest and the visibility impact is immediate and measurable.

## Key Points

- Always validate structured data with Google's Rich Results Test (https://search.google.com/test/rich-results) before deploying. Invalid markup is silently ignored by search engines.
- Keep structured data in sync with visible page content. Google penalizes markup that describes content not visible to users (e.g., fake reviews or prices that differ from what is displayed).
- Use the `@id` pattern to cross-reference entities within a `@graph` block, creating a connected entity graph that search engines can traverse.
- Marking up content that is not visible on the page. Google's guidelines require structured data to reflect user-visible content; violations can result in manual actions.

## Quick Example

```bash
# Test a live URL
npx structured-data-testing-tool --url https://example.com/product/widget

# Test local HTML file
npx structured-data-testing-tool --file ./out/product/widget.html
```
skilldb get seo-content-skills/Structured Data Schema OrgFull skill: 232 lines
Paste into your CLAUDE.md or agent config

Structured Data & Schema.org — SEO & Content

Core Philosophy

Structured data is the bridge between your page content and search engine understanding. When implemented correctly via JSON-LD, it enables rich results -- star ratings, FAQ accordions, breadcrumb trails, product prices -- that directly increase click-through rates without changing your algorithmic ranking. The ROI of structured data is one of the highest in SEO because the implementation effort is modest and the visibility impact is immediate and measurable.

JSON-LD is the industry standard for structured data because it separates markup from HTML, making it easier to maintain, debug, and generate dynamically. Google explicitly recommends JSON-LD over Microdata and RDFa. A reusable JsonLd component in your React or Next.js application that accepts typed data objects is the cleanest implementation pattern.

Structured data must always reflect user-visible content. Google penalizes markup that describes content not shown on the page -- fake reviews, prices that differ from displayed values, or FAQ content hidden from users. The structured data is a machine-readable description of what the human sees, not an opportunity to inject additional information for search engines.

You are an expert in Schema.org structured data markup for SEO, specializing in JSON-LD implementation, rich result eligibility, and search engine validation.

Overview

Structured data uses a standardized vocabulary (Schema.org) to annotate web page content so search engines can understand entities, relationships, and attributes. When implemented correctly via JSON-LD, structured data enables rich results in Google Search — star ratings, FAQ accordions, breadcrumb trails, product prices, recipe cards, and more. This directly increases click-through rates and search visibility without changing page rankings algorithmically.

Core Concepts

JSON-LD as the Preferred Format

Google recommends JSON-LD (JavaScript Object Notation for Linked Data) over Microdata or RDFa. JSON-LD is injected as a <script> block, keeping markup separate from HTML structure.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Understanding Structured Data",
  "datePublished": "2026-01-15T08:00:00+00:00",
  "dateModified": "2026-03-10T12:00:00+00:00",
  "author": {
    "@type": "Person",
    "name": "Jane Smith",
    "url": "https://example.com/authors/jane-smith"
  }
}
</script>

Schema Types That Trigger Rich Results

Schema TypeRich ResultKey Required Fields
ArticleArticle snippetheadline, datePublished, author
ProductProduct card with price/ratingname, offers, aggregateRating
FAQPageExpandable FAQ accordionmainEntity[].name, mainEntity[].acceptedAnswer
BreadcrumbListBreadcrumb trailitemListElement[].name, itemListElement[].item
HowToStep-by-step instructionsname, step[].text
LocalBusinessBusiness panelname, address, telephone
OrganizationKnowledge panelname, url, logo
ReviewStar ratingsreviewRating, author, itemReviewed
EventEvent listingname, startDate, location
VideoObjectVideo carouselname, uploadDate, thumbnailUrl

The @graph Pattern for Multiple Entities

When a page has multiple schema types, use @graph to bundle them in a single JSON-LD block:

{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "WebPage",
      "@id": "https://example.com/product/widget#webpage",
      "name": "Widget Product Page",
      "isPartOf": { "@id": "https://example.com/#website" }
    },
    {
      "@type": "Product",
      "name": "Widget Pro",
      "offers": {
        "@type": "Offer",
        "price": "49.99",
        "priceCurrency": "USD",
        "availability": "https://schema.org/InStock"
      }
    },
    {
      "@type": "BreadcrumbList",
      "itemListElement": [
        { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.com/" },
        { "@type": "ListItem", "position": 2, "name": "Products", "item": "https://example.com/products/" },
        { "@type": "ListItem", "position": 3, "name": "Widget Pro" }
      ]
    }
  ]
}

Implementation Patterns

Reusable JSON-LD Component (React/Next.js)

// components/structured-data.tsx
type JsonLdProps = {
  data: Record<string, unknown> | Record<string, unknown>[];
};

export function JsonLd({ data }: JsonLdProps) {
  const jsonLd = Array.isArray(data)
    ? { "@context": "https://schema.org", "@graph": data }
    : { "@context": "https://schema.org", ...data };

  return (
    <script
      type="application/ld+json"
      dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
    />
  );
}

FAQ Page Schema

interface FaqItem {
  question: string;
  answer: string;
}

export function faqSchema(items: FaqItem[]) {
  return {
    "@type": "FAQPage",
    mainEntity: items.map((item) => ({
      "@type": "Question",
      name: item.question,
      acceptedAnswer: {
        "@type": "Answer",
        text: item.answer,
      },
    })),
  };
}

Product Schema with Offers

interface ProductData {
  name: string;
  description: string;
  image: string;
  sku: string;
  price: number;
  currency: string;
  availability: "InStock" | "OutOfStock" | "PreOrder";
  ratingValue?: number;
  reviewCount?: number;
}

export function productSchema(product: ProductData) {
  return {
    "@type": "Product",
    name: product.name,
    description: product.description,
    image: product.image,
    sku: product.sku,
    offers: {
      "@type": "Offer",
      price: product.price.toFixed(2),
      priceCurrency: product.currency,
      availability: `https://schema.org/${product.availability}`,
      url: typeof window !== "undefined" ? window.location.href : undefined,
    },
    ...(product.ratingValue && {
      aggregateRating: {
        "@type": "AggregateRating",
        ratingValue: product.ratingValue,
        reviewCount: product.reviewCount,
      },
    }),
  };
}

Breadcrumb Schema from URL Path

export function breadcrumbSchema(
  segments: { name: string; url: string }[]
) {
  return {
    "@type": "BreadcrumbList",
    itemListElement: segments.map((segment, index) => ({
      "@type": "ListItem",
      position: index + 1,
      name: segment.name,
      ...(index < segments.length - 1 ? { item: segment.url } : {}),
    })),
  };
}

Validation with Google's Rich Results Test API

# Test a live URL
npx structured-data-testing-tool --url https://example.com/product/widget

# Test local HTML file
npx structured-data-testing-tool --file ./out/product/widget.html

Use Google Search Console's "Enhancements" reports to monitor structured data errors across the entire site after deployment.

Best Practices

  • Always validate structured data with Google's Rich Results Test (https://search.google.com/test/rich-results) before deploying. Invalid markup is silently ignored by search engines.
  • Keep structured data in sync with visible page content. Google penalizes markup that describes content not visible to users (e.g., fake reviews or prices that differ from what is displayed).
  • Use the @id pattern to cross-reference entities within a @graph block, creating a connected entity graph that search engines can traverse.

Anti-Patterns

  • Invisible markup: Adding structured data for content that is not visible on the page. Google's guidelines require structured data to reflect user-visible content, and violations can result in manual actions that remove rich results entirely.
  • Using Microdata or RDFa instead of JSON-LD: While technically valid, these formats interleave with HTML and are harder to maintain, debug, and generate dynamically. JSON-LD as a separate script block is cleaner and Google-recommended.
  • Skipping validation before deployment: Pushing structured data to production without testing with Google's Rich Results Test. Invalid markup is silently ignored by search engines, providing zero benefit while creating a false sense of implementation.
  • Stale structured data: Letting structured data drift out of sync with page content after product updates, price changes, or content edits. Structured data must be generated dynamically from the same data source as the page content.
  • Separate JSON-LD blocks per entity: Using multiple <script type="application/ld+json"> blocks on a single page instead of bundling entities into a single @graph array. The graph pattern creates a connected entity model that search engines can traverse more effectively.

Common Pitfalls

  • Marking up content that is not visible on the page. Google's guidelines require structured data to reflect user-visible content; violations can result in manual actions.
  • Using Microdata or RDFa instead of JSON-LD. While technically valid, these formats interleave with HTML and are harder to maintain, debug, and generate dynamically. JSON-LD is the industry standard.

Install this skill directly: skilldb add seo-content-skills

Get CLI access →