Knowing the Schema.org vocabulary exists is not enough. Advanced practitioners know which types unlock rich results in Google Search, how to author them correctly, and what actually governs eligibility. This module walks through every major rich-result-eligible type you will encounter professionally, with precise property requirements and realistic JSON-LD examples for each.
Before diving into individual types, internalise this rule: passing the Rich Results Test does not guarantee rich results. Google's documentation states explicitly that eligible markup may trigger enhanced presentation at Google's discretion. Factors that influence whether rich results actually appear include:
Validate with the Rich Results Test (search.google.com/test/rich-results) for Google eligibility and the Schema Markup Validator (validator.schema.org) for general schema correctness. Use both — they catch different things.
The Article type (and its subtypes NewsArticle, BlogPosting) signals editorial content to Google. It supports enhanced display in Google Discover, the Top Stories carousel, and on some devices as richer snippets.
Required / strongly recommended properties:
headline — the article title (max 110 characters for Top Stories)image — at minimum one ImageObject with url, width, and height; provide multiple aspect ratios (16:9, 4:3, 1:1) for DiscoverdatePublished and dateModified — ISO 8601 with timezone (2024-05-15T09:00:00+01:00)author — a Person or Organization entity with name and ideally a resolvable url or @idpublisher — typically your site's Organization entity (reference it by @id){
"@context": "https://schema.org",
"@type": "Article",
"@id": "https://example.com/seo/core-web-vitals/#article",
"headline": "Core Web Vitals: The Complete 2024 Guide",
"image": [
{
"@type": "ImageObject",
"url": "https://example.com/img/cwv-guide-16x9.jpg",
"width": 1600,
"height": 900
},
{
"@type": "ImageObject",
"url": "https://example.com/img/cwv-guide-1x1.jpg",
"width": 800,
"height": 800
}
],
"datePublished": "2024-01-10T08:00:00+00:00",
"dateModified": "2024-05-15T14:30:00+01:00",
"author": {
"@type": "Person",
"@id": "https://example.com/team/jane-smith/",
"name": "Jane Smith",
"url": "https://example.com/team/jane-smith/"
},
"publisher": {
"@id": "https://example.com/#organization"
}
}
Use NewsArticle for time-sensitive news from a recognised publisher. Use BlogPosting for informal posts. The technical markup is near-identical; subtype choice tells Google about content nature.
Product markup is among the most commercially valuable schema types. It can unlock star ratings, price, availability, and shipping information directly in the SERP. Google now also uses Product markup to populate the Shopping Graph. This type requires careful nesting.
Core structure:
Product — the parent entity (name, image, description, sku, brand)Offer — nested inside Product.offers; carries price, priceCurrency, availability, url, priceValidUntilAggregateRating — nested inside Product.aggregateRating; carries ratingValue, reviewCount or ratingCount, bestRating, worstRatingReview — nested in Product.review; individual reviews with author, reviewRating, and reviewBodyCritical rules Google enforces:
price and availability in markup must match the visible on-page price and stock status — automated price mismatches are a common penalty triggerpriceValidUntil must be a future date; expired dates can suppress the rich resultavailability values from Schema.org: https://schema.org/InStock, https://schema.org/OutOfStock, etc.{
"@context": "https://schema.org",
"@type": "Product",
"@id": "https://example.com/products/noise-cancelling-headphones/#product",
"name": "ProSound NC-900 Wireless Headphones",
"image": "https://example.com/img/nc-900-main.jpg",
"description": "Industry-leading 40dB active noise cancellation with 30-hour battery life.",
"sku": "NC900-BLK",
"brand": {
"@type": "Brand",
"name": "ProSound"
},
"offers": {
"@type": "Offer",
"url": "https://example.com/products/noise-cancelling-headphones/",
"price": "299.00",
"priceCurrency": "GBP",
"priceValidUntil": "2024-12-31",
"availability": "https://schema.org/InStock",
"seller": {
"@id": "https://example.com/#organization"
}
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.7",
"reviewCount": "312",
"bestRating": "5",
"worstRating": "1"
},
"review": {
"@type": "Review",
"author": {
"@type": "Person",
"name": "Marcus T."
},
"reviewRating": {
"@type": "Rating",
"ratingValue": "5",
"bestRating": "5"
},
"reviewBody": "The noise cancellation is truly remarkable for open-plan offices."
}
}
FAQPage markup can produce an expanded accordion in the SERP directly beneath your listing, dramatically increasing real estate. It is one of the easiest types to implement but also one of the most abused — Google has restricted its display following widespread misuse.
Rules Google applies:
QAPage instead{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What is LCP and what is a good score?",
"acceptedAnswer": {
"@type": "Answer",
"text": "LCP (Largest Contentful Paint) measures how long the largest visible element takes to render. Google considers a score under 2.5 seconds 'Good', 2.5–4s 'Needs Improvement', and over 4s 'Poor'."
}
},
{
"@type": "Question",
"name": "Does page speed affect Google rankings?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes. Core Web Vitals are a confirmed Google ranking signal as part of the Page Experience update. Pages in the 'Poor' threshold may rank lower than comparable pages with 'Good' scores."
}
}
]
}
HowTo can render as a step-by-step rich result with images in Google Search and Google Assistant. It is appropriate for genuinely procedural content where steps must be followed in sequence. Like FAQ, its SERP appearance has become less consistent — Google may show it selectively.
Key properties:
name — the title of the how-to guidestep — an array of HowToStep objects, each with name, text, and optionally image and urltotalTime — ISO 8601 duration, e.g. PT30M for 30 minutesestimatedCost — a MonetaryAmount or plain texttool and supply — arrays of HowToTool and HowToSupply{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "How to Submit Your Sitemap to Google Search Console",
"totalTime": "PT10M",
"step": [
{
"@type": "HowToStep",
"position": 1,
"name": "Open Google Search Console",
"text": "Sign in to search.google.com/search-console and select the property you want to manage.",
"url": "https://example.com/guides/sitemap-submission/#step-1"
},
{
"@type": "HowToStep",
"position": 2,
"name": "Navigate to Sitemaps",
"text": "In the left navigation panel, click 'Indexing' then 'Sitemaps'.",
"url": "https://example.com/guides/sitemap-submission/#step-2"
},
{
"@type": "HowToStep",
"position": 3,
"name": "Enter and submit your sitemap URL",
"text": "Type your sitemap URL (e.g. /sitemap.xml) in the 'Add a new sitemap' field and click Submit.",
"url": "https://example.com/guides/sitemap-submission/#step-3"
}
]
}
BreadcrumbList is the most universally applicable rich result type. It replaces the raw URL in the SERP snippet with a human-readable breadcrumb path, improving click-through rates by communicating site structure at a glance. It is simple, safe, and should be implemented on nearly every page of a structured site.
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://example.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "SEO Guides",
"item": "https://example.com/seo-guides/"
},
{
"@type": "ListItem",
"position": 3,
"name": "Structured Data",
"item": "https://example.com/seo-guides/structured-data/"
}
]
}
The final ListItem represents the current page. The item property on the last breadcrumb is technically optional per Google's documentation but including it is best practice for consistency and entity clarity.
Organization is the foundational entity for your site. It does not produce traditional rich results, but it is central to entity SEO — it tells the Knowledge Graph what your brand is, where it operates, and how to disambiguate it from other entities with similar names. Place it on your homepage and reference it by @id across every other type you implement.
Key properties:
@id — a stable, unique IRI for your organisation, typically https://yoursite.com/#organizationname, url, logo (as ImageObject)sameAs — an array of URLs to your authoritative profiles: Wikipedia, Wikidata, LinkedIn, Twitter/X, Crunchbase, Companies House, etc.contactPoint for support/sales contactsfoundingDate, numberOfEmployees, description{
"@context": "https://schema.org",
"@type": "Organization",
"@id": "https://example.com/#organization",
"name": "Example Agency",
"url": "https://example.com/",
"logo": {
"@type": "ImageObject",
"url": "https://example.com/img/logo.png",
"width": 400,
"height": 60
},
"foundingDate": "2015",
"description": "A technical SEO agency specialising in JavaScript rendering and Core Web Vitals.",
"sameAs": [
"https://en.wikipedia.org/wiki/Example_Agency",
"https://www.wikidata.org/wiki/Q12345678",
"https://www.linkedin.com/company/example-agency",
"https://twitter.com/exampleagency"
],
"contactPoint": {
"@type": "ContactPoint",
"contactType": "customer support",
"email": "[email protected]",
"availableLanguage": "English"
}
}
Pair Organization with WebSite on your homepage to enable Sitelinks Search Box eligibility (though Google controls whether it appears):
{
"@context": "https://schema.org",
"@type": "WebSite",
"@id": "https://example.com/#website",
"url": "https://example.com/",
"name": "Example Agency",
"publisher": {
"@id": "https://example.com/#organization"
},
"potentialAction": {
"@type": "SearchAction",
"target": {
"@type": "EntryPoint",
"urlTemplate": "https://example.com/search?q={search_term_string}"
},
"query-input": "required name=search_term_string"
}
}
LocalBusiness (and its subtypes like Restaurant, MedicalBusiness, LegalService) is critical for local SEO. It enriches your Knowledge Panel and local pack signals. A LocalBusiness entity extends Organization, so it shares many of the same properties plus location-specific ones.
Additional key properties:
address — a PostalAddress with streetAddress, addressLocality, addressRegion, postalCode, addressCountrygeo — a GeoCoordinates with latitude and longitudetelephone in E.164 format (+441234567890)openingHoursSpecification — an array of OpeningHoursSpecification objectspriceRange — a string like ££ or $–$$aggregateRating — nested rating from your own on-page reviews{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"@id": "https://example.com/#localbusiness",
"name": "Example Dental Clinic",
"url": "https://example.com/",
"telephone": "+441512345678",
"priceRange": "££",
"address": {
"@type": "PostalAddress",
"streetAddress": "42 King Street",
"addressLocality": "Liverpool",
"addressRegion": "Merseyside",
"postalCode": "L1 1AA",
"addressCountry": "GB"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 53.4084,
"longitude": -2.9916
},
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
"opens": "09:00",
"closes": "18:00"
},
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": "Saturday",
"opens": "09:00",
"closes": "13:00"
}
],
"sameAs": [
"https://www.google.com/maps?cid=123456789"
]
}
NAP consistency rule: The name, address, and telephone in your structured data must exactly match your Google Business Profile. Discrepancies confuse the entity graph and weaken local signals.
Event markup produces rich results in Google Search and Google Events. It is eligible for the "Events from the web" feature and can appear in the events carousel for relevant queries.
Required properties:
name, startDate (ISO 8601 with timezone), endDatelocation — a Place with a PostalAddress for in-person events, or a VirtualLocation with a url for online eventseventStatus — one of EventScheduled, EventPostponed, EventCancelled, EventMovedOnlineeventAttendanceMode — OfflineEventAttendanceMode, OnlineEventAttendanceMode, or MixedEventAttendanceModeorganizer — a Person or Organization{
"@context": "https://schema.org",
"@type": "Event",
"name": "Advanced Technical SEO Workshop",
"startDate": "2024-09-18T10:00:00+01:00",
"endDate": "2024-09-18T16:30:00+01:00",
"eventStatus": "https://schema.org/EventScheduled",
"eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode",
"location": {
"@type": "Place",
"name": "The Digital Hub",
"address": {
"@type": "PostalAddress",
"streetAddress": "10 Tech Square",
"addressLocality": "Manchester",
"postalCode": "M1 2AB",
"addressCountry": "GB"
}
},
"organizer": {
"@id": "https://example.com/#organization"
},
"offers": {
"@type": "Offer",
"url": "https://example.com/events/seo-workshop/tickets/",
"price": "199",
"priceCurrency": "GBP",
"availability": "https://schema.org/InStock",
"validFrom": "2024-07-01T00:00:00+01:00"
}
}
Recipe is one of the richest rich result types — it can display cook time, calories, ratings, and images directly in the SERP and dominate the visual carousel for food-related queries. It is essential for any food publisher.
{
"@context": "https://schema.org",
"@type": "Recipe",
"name": "Classic Sourdough Loaf",
"image": "https://example.com/img/sourdough.jpg",
"author": {
"@type": "Person",
"name": "Emma Bakes"
},
"datePublished": "2024-03-22",
"description": "A tangy, open-crumbed sourdough made with 78% hydration dough and a 20-hour cold ferment.",
"prepTime": "PT30M",
"cookTime": "PT50M",
"totalTime": "PT20H50M",
"keywords": "sourdough, bread, artisan",
"recipeYield": "1 loaf",
"recipeCategory": "Bread",
"recipeCuisine": "European",
"nutrition": {
"@type": "NutritionInformation",
"calories": "210 calories",
"servingSize": "1 slice (50g)"
},
"recipeIngredient": [
"500g strong white bread flour",
"390ml water",
"100g active sourdough starter",
"10g fine sea salt"
],
"recipeInstructions": [
{
"@type": "HowToStep",
"name": "Autolyse",
"text": "Combine flour and 350ml of the water. Mix until no dry flour remains. Rest 1 hour.",
"timeRequired": "PT1H"
},
{
"@type": "HowToStep",
"name": "Add starter and salt",
"text": "Add the starter and salt with remaining water. Incorporate fully using the pinch-and-fold method."
}
],
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.9",
"ratingCount": "241"
}
}
VideoObject markup helps Google index video content and surface it with thumbnail, duration, and upload date in video-rich results and Google Video Search. It is essential for any page where video is the primary content.
Required properties:
name, description, thumbnailUrl, uploadDateStrongly recommended:
duration — ISO 8601 duration (PT8M30S = 8 minutes 30 seconds)contentUrl — direct URL to the video fileembedUrl — the embed player URLhasPart — array of Clip objects with timestamps for Key Moments in Search{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "How to Read a Log File for SEO — Step by Step",
"description": "In this tutorial we walk through parsing an Apache access log in Python to identify Googlebot behaviour patterns and crawl waste.",
"thumbnailUrl": "https://example.com/img/log-file-tutorial-thumb.jpg",
"uploadDate": "2024-04-10T12:00:00+01:00",
"duration": "PT14M52S",
"contentUrl": "https://example.com/videos/log-file-seo.mp4",
"embedUrl": "https://www.youtube.com/embed/dQw4w9WgXcQ",
"publisher": {
"@id": "https://example.com/#organization"
},
"hasPart": [
{
"@type": "Clip",
"name": "Understanding the log format",
"startOffset": 0,
"endOffset": 120,
"url": "https://example.com/videos/log-file-seo/?t=0"
},
{
"@type": "Clip",
"name": "Filtering for Googlebot requests",
"startOffset": 121,
"endOffset": 390,
"url": "https://example.com/videos/log-file-seo/?t=121"
}
]
}
Person is not a rich-result type in the traditional sense, but it is foundational for E-E-A-T (Experience, Expertise, Authoritativeness, Trustworthiness). Linking article content to a well-defined Person entity — one with a Knowledge Panel, verifiable credentials, and a consistent @id — helps Google assess author credibility. This is particularly important for YMYL (Your Money, Your Life) topics.
{
"@context": "https://schema.org",
"@type": "Person",
"@id": "https://example.com/team/jane-smith/",
"name": "Jane Smith",
"url": "https://example.com/team/jane-smith/",
"jobTitle": "Technical SEO Director",
"worksFor": {
"@id": "https://example.com/#organization"
},
"image": "https://example.com/img/jane-smith-headshot.jpg",
"sameAs": [
"https://www.linkedin.com/in/jane-smith-seo",
"https://twitter.com/janesmith_seo",
"https://en.wikipedia.org/wiki/Jane_Smith_(SEO)"
],
"knowsAbout": [
"Technical SEO",
"JavaScript rendering",
"Core Web Vitals"
]
}
When architecting structured data at scale, you need a clear decision of which types belong on which page templates. The table below represents a starting point — your implementation will depend on what content is genuinely present on each template type.
Organization, WebSiteArticle (or BlogPosting), BreadcrumbList, Person (author)NewsArticle, BreadcrumbList, Person (author)Product + Offer + AggregateRating, BreadcrumbList, optionally FAQPage if FAQ section is presentBreadcrumbList, optionally ItemListLocalBusiness, BreadcrumbListEvent, BreadcrumbListRecipe, BreadcrumbListVideoObject, Article or BreadcrumbListFAQPage, BreadcrumbListHowTo, BreadcrumbListPerson"author": "Jane Smith" instead of a Person object with name) passes some validators but produces weaker entity signals.@type declarations on the same entity without proper union typing.Review.itemReviewed used differently across versions.Hand-author a complete JSON-LD block for a hypothetical product page for a book sold by an independent retailer. Your block must include, with correct nesting and no validation errors:
Product with correct Brand nesting and skuOffer with price, currency, availability, and a priceValidUntil at least 90 days in the futureAggregateRating with all four rating propertiesReview with a nested RatingBreadcrumbList of three levelsOrganization referenced via @id as the sellerValidate the entire block in both the Rich Results Test and the Schema Markup Validator. Fix any warnings before considering it complete.
Given a page brief (e.g., a recipe page, a local dentist page, or a software product page), you can:
When you can do all five without referring to documentation, you are ready to move to Module 3.3 — Nesting, @id Referencing, and Building a Connected Entity Graph.