Schema.org Structured Data & JSON-LD
JSON-LD Fundamentals
JSON-LD (JavaScript Object Notation for Linked Data) is Google's recommended format for structured data. It is injected via a
tag in the
or
of an HTML page.
Basic Syntax
html
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "How to Implement Structured Data",
"author": {
"@type": "Person",
"name": "Jane Smith"
}
}
</script>
Core Keywords
| Keyword | Purpose | Example |
|---|
| Declares the vocabulary (always ) | "@context": "https://schema.org"
|
| Specifies the entity type | |
| Unique identifier for an entity (enables cross-referencing) | "@id": "https://example.com/#organization"
|
| Contains multiple entities in a single JSON-LD block | "@graph": [{ ... }, { ... }]
|
Nesting Entities
Entities can be nested directly or referenced by
:
json
{
"@context": "https://schema.org",
"@type": "Article",
"author": {
"@type": "Person",
"name": "Jane Smith",
"@id": "https://example.com/#jane"
},
"publisher": {
"@id": "https://example.com/#organization"
}
}
Arrays
Use arrays when a property has multiple values:
json
{
"@type": "Article",
"author": [
{ "@type": "Person", "name": "Jane Smith" },
{ "@type": "Person", "name": "John Doe" }
]
}
The @graph Pattern (Multi-Entity Pages)
Use
to describe multiple entities on a single page (e.g., Organization + WebPage + BreadcrumbList):
json
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": "https://example.com/#organization",
"name": "Example Corp",
"url": "https://example.com"
},
{
"@type": "WebPage",
"@id": "https://example.com/about/#webpage",
"url": "https://example.com/about/",
"name": "About Us",
"isPartOf": { "@id": "https://example.com/#website" }
},
{
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.com/" },
{ "@type": "ListItem", "position": 2, "name": "About" }
]
}
]
}
Google-Supported Schema Types
The following types are recognized by Google and can trigger rich results. Each section lists required (R) and recommended (Rec) properties.
Article (NewsArticle, BlogPosting)
Triggers: article rich result with headline, image, date in search.
| Property | Status | Notes |
|---|
| R | Max 110 characters |
| R | At least 696px wide; multiple images recommended |
| R | ISO 8601 format |
| Rec | ISO 8601 format |
| R | Person or Organization with and |
| Rec | Organization with and |
| Rec | Short summary of the article |
| Rec | URL of the page |
MCP Tool: Use
on any article URL to see its current structured data, then
with type
to produce compliant markup.
Product (with Offer, AggregateRating)
Triggers: product rich result with price, availability, rating stars.
| Property | Status | Notes |
|---|
| R | Product name |
| R | At least one image |
| Rec | Product description |
| Rec | Stock-keeping unit |
| Rec | Brand name |
| R | Offer or AggregateOffer |
| R | Numeric price |
| R | ISO 4217 currency code |
| R | ItemAvailability enum (e.g., https://schema.org/InStock
) |
| Rec | URL to buy |
| Rec | AggregateRating with and |
| Rec | Individual Review objects |
Nesting pattern: and
nest inside
:
json
{
"@type": "Product",
"name": "Widget",
"offers": {
"@type": "Offer",
"price": "29.99",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.5",
"reviewCount": "120"
}
}
FAQPage (with Question / Answer)
Triggers: expandable FAQ accordion in search results.
| Property | Status | Notes |
|---|
| R | Array of Question objects |
| R | The question text |
| R | Answer object |
| R | The answer text (HTML allowed) |
Rules:
- Only use FAQPage for pages where the primary content is a list of questions and answers.
- Each question and answer must be visible on the page.
- Do not use for forums or single-question pages (use QAPage instead).
HowTo (with HowToStep)
Triggers: step-by-step rich result or carousel.
| Property | Status | Notes |
|---|
| R | Title of the how-to |
| R | Array of HowToStep objects |
| R | Step title |
| R | Step instructions |
| Rec | Image for each step |
| Rec | URL anchor to step on page |
| Rec | ISO 8601 duration (e.g., ) |
| Rec | MonetaryAmount object |
| Rec | HowToSupply items needed |
| Rec | HowToTool items needed |
LocalBusiness (and Subtypes)
Triggers: local knowledge panel, map pack eligibility data.
| Property | Status | Notes |
|---|
| R | Business name |
| R | PostalAddress object |
| Rec | Phone number |
openingHoursSpecification
| Rec | Array of hours |
| Rec | GeoCoordinates (lat/long) |
| Rec | Website URL |
| Rec | Business photo |
| Rec | e.g., or |
| Rec | For Restaurant subtype |
| Rec | AggregateRating |
| Rec | Review objects |
Organization
Triggers: knowledge panel data, logo in search results.
| Property | Status | Notes |
|---|
| R | Organization name |
| R | Website URL |
| R | ImageObject or URL (min 112x112px, square preferred) |
| Rec | Array of social profile URLs |
| Rec | ContactPoint object |
| Rec | PostalAddress |
| Rec | Short description |
| Rec | ISO 8601 date |
BreadcrumbList
Triggers: breadcrumb trail in search results replacing the URL.
| Property | Status | Notes |
|---|
| R | Array of ListItem objects |
| R | Integer (1-indexed) |
| R | Breadcrumb label |
| R* | URL (*omit on last item) |
WebSite (with SearchAction for Sitelinks Search Box)
Triggers: sitelinks search box on branded queries.
| Property | Status | Notes |
|---|
| R | Homepage URL |
| Rec | Site name |
| R | SearchAction object |
| R | URL template with |
| R | "required name=search_term_string"
|
json
{
"@type": "WebSite",
"url": "https://example.com/",
"potentialAction": {
"@type": "SearchAction",
"target": "https://example.com/search?q={search_term_string}",
"query-input": "required name=search_term_string"
}
}
Event
Triggers: event rich result with date, location, ticket info.
| Property | Status | Notes |
|---|
| R | Event name |
| R | ISO 8601 datetime |
| R | Place or VirtualLocation |
| R | Venue name |
| R | PostalAddress |
| Rec | ISO 8601 datetime |
| Rec | Event description |
| Rec | Event image |
| Rec | Offer with price/url/availability |
| Rec | Person or Organization |
| Rec | Person or Organization |
| Rec | EventScheduled, EventCancelled, EventPostponed, etc. |
| Rec | OfflineEventAttendanceMode, OnlineEventAttendanceMode, MixedEventAttendanceMode |
Recipe
Triggers: recipe rich result with image, rating, cook time.
| Property | Status | Notes |
|---|
| R | Recipe name |
| R | Multiple images at different aspect ratios |
| R | Person or Organization |
| Rec | ISO 8601 |
| Rec | Short description |
| Rec | ISO 8601 duration |
| Rec | ISO 8601 duration |
| Rec | ISO 8601 duration |
| Rec | e.g., |
| Rec | Array of strings |
| R | Array of HowToStep objects |
| Rec | NutritionInformation (calories) |
| Rec | AggregateRating |
| Rec | VideoObject |
VideoObject
Triggers: video rich result with thumbnail, duration, upload date.
| Property | Status | Notes |
|---|
| R | Video title |
| R | Video description |
| R | Thumbnail image URL |
| R | ISO 8601 date |
| Rec | Direct URL to video file |
| Rec | Embed URL |
| Rec | ISO 8601 duration |
| Rec | View count |
Course
Triggers: course rich result in search and Google for Education.
| Property | Status | Notes |
|---|
| R | Course title |
| R | Course description |
| R | Organization offering the course |
| Rec | Offer with price |
| Rec | Identifier |
| Rec | CourseInstance with schedule |
SoftwareApplication
Triggers: software rich result with rating, price, OS.
| Property | Status | Notes |
|---|
| R | App name |
| Rec | e.g., , |
| Rec | e.g., , |
| R | Offer with price (use for free) |
| Rec | AggregateRating |
| Rec | Review objects |
Review
Triggers: review snippet with star rating.
| Property | Status | Notes |
|---|
| R | The entity being reviewed (Product, LocalBusiness, etc.) |
| R | Person who wrote the review |
| R | Rating object with |
| Rec | Maximum rating value |
| Rec | Minimum rating value |
| Rec | ISO 8601 date |
| Rec | Full text of the review |
Dynamic Schema Generation Patterns
When building pages programmatically, generate schema from your data models:
Server-Side Rendering (Next.js example)
jsx
export default function ProductPage({ product }) {
const schema = {
"@context": "https://schema.org",
"@type": "Product",
"name": product.title,
"image": product.images,
"description": product.description,
"sku": product.sku,
"brand": { "@type": "Brand", "name": product.brand },
"offers": {
"@type": "Offer",
"price": product.price,
"priceCurrency": "USD",
"availability": product.inStock
? "https://schema.org/InStock"
: "https://schema.org/OutOfStock"
}
};
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
{/* Page content */}
</>
);
}
CMS Integration Pattern
For WordPress, Shopify, or headless CMS:
- Map CMS fields to schema properties in a template or plugin.
- Ensure price, availability, and rating data are pulled from the live data source.
- Use conditional logic to only output properties that have values.
Validation Approach
Step 1: Rich Results Test (Google)
- URL: https://search.google.com/test/rich-results
- Tests if your markup qualifies for rich results.
- Reports errors and warnings per schema type.
Step 2: Schema Markup Validator (Schema.org)
- URL: https://validator.schema.org/
- Validates against the full Schema.org vocabulary (broader than Google).
Step 3: Google Search Console
- Check Enhancements section for structured data reports.
- Monitor errors, warnings, and valid item counts.
- Review indexing of pages with structured data.
MCP Tool: Use
on any URL to pull all JSON-LD, Microdata, and RDFa. Use
with a target type to produce valid markup from page content.
Common Pitfalls
| Pitfall | Problem | Fix |
|---|
| Invisible content | Schema describes content not visible to users | Ensure every structured data property matches visible page content |
| Missing required fields | Google ignores incomplete markup | Always include all required properties per type |
| Wrong | Using a type Google does not support for rich results | Use only Google-documented types |
| Fake reviews | Schema includes fabricated ratings or reviews | Only mark up genuine, real user reviews |
| Outdated prices | Product schema shows old price | Dynamically generate schema from live data |
| Multiple conflicting types | Two Product schemas on one page with different data | Use one canonical schema per entity |
| Self-referencing issues | references that point nowhere | Ensure every reference has a matching definition |
| Incorrect date format | Using instead of ISO 8601 | Always use or YYYY-MM-DDTHH:MM:SS+00:00
|
| HTTP image URLs | Images referenced over HTTP not HTTPS | Use HTTPS URLs for all images |
| Spam policy violations | Marking up content solely for SEO manipulation | Follow Google's structured data spam policies |
Related Skills
- seo-on-page-optimization -- for content and meta tag optimization
- seo-technical-audit -- for crawlability and indexing issues
- seo-mcp-tools-expert -- for detailed MCP tool usage
Key MCP Tools for Structured Data
| Tool | Use For |
|---|
| Extract existing structured data from any URL |
| Generate valid JSON-LD markup for a given page and type |
See SCHEMA_TEMPLATES.md for ready-to-use JSON-LD templates.
See VALIDATION_RULES.md for Google's validation requirements.
See RICH_RESULTS_GUIDE.md for which types trigger which rich results.