Product Schema
Last reviewed:
Add to each product detail page as <script type="application/ld+json">. Product identifiers (sku, mpn, gtin8/gtin12/gtin13) are the matching keys search engines use to connect product pages to their product knowledge graphs — missing identifiers get the product treated as an unmatched listing even when everything else validates.
Google Shopping variation
Extends the standard rich result with shippingDetails and hasMerchantReturnPolicy, both required for free-listing eligibility on the Shopping tab. A valid GTIN is required for most categories — without one, Google can’t match the product to its catalog.
{
"@context": "https://schema.org",
"@type": "Product",
"name": "REQUIRED — product name as displayed on the page",
"description": "REQUIRED — concise description; must match visible page content",
"image": ["REQUIRED — absolute URL to product image, minimum 250x250 px"],
"brand": { "@type": "Brand", "name": "REQUIRED — brand name" },
"gtin13": "REQUIRED for most categories — 13-digit EAN; use gtin8/gtin12/gtin14 as appropriate",
"mpn": "CONDITIONAL — required when no GTIN exists; always pair with brand",
"sku": "RECOMMENDED — your internal SKU",
"offers": {
"@type": "Offer",
"url": "REQUIRED — canonical URL of this product page",
"priceCurrency": "REQUIRED — ISO 4217, e.g. USD",
"price": "REQUIRED — numeric only, e.g. 29.99",
"priceValidUntil": "REQUIRED — YYYY-MM-DD; a missing or past date causes suppression",
"availability": "REQUIRED — https://schema.org/InStock",
"itemCondition": "REQUIRED — https://schema.org/NewCondition",
"seller": { "@type": "Organization", "name": "REQUIRED — seller name" },
"shippingDetails": {
"@type": "OfferShippingDetails",
"shippingRate": { "@type": "MonetaryAmount", "value": "REQUIRED — numeric cost, e.g. 4.99; use 0 for free shipping", "currency": "REQUIRED — ISO 4217, e.g. USD" },
"shippingDestination": { "@type": "DefinedRegion", "addressCountry": "REQUIRED — ISO 3166-1 alpha-2, e.g. US" },
"deliveryTime": {
"@type": "ShippingDeliveryTime",
"handlingTime": { "@type": "QuantitativeValue", "minValue": "RECOMMENDED — integer, minimum handling days, e.g. 0", "maxValue": "RECOMMENDED — integer, maximum handling days, e.g. 1", "unitCode": "DAY" },
"transitTime": { "@type": "QuantitativeValue", "minValue": "RECOMMENDED — integer, minimum transit days, e.g. 3", "maxValue": "RECOMMENDED — integer, maximum transit days, e.g. 5", "unitCode": "DAY" }
}
},
"hasMerchantReturnPolicy": {
"@type": "MerchantReturnPolicy",
"applicableCountry": "REQUIRED — ISO 3166-1 alpha-2, e.g. US",
"returnPolicyCategory": "REQUIRED — https://schema.org/MerchantReturnFiniteReturnWindow",
"merchantReturnDays": "REQUIRED for finite window — integer days, e.g. 30",
"returnMethod": "REQUIRED — https://schema.org/ReturnByMail",
"returnFees": "REQUIRED — https://schema.org/FreeReturn"
}
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "REQUIRED if shown — numeric 0-5",
"reviewCount": "REQUIRED if shown — integer count of reviews"
}
}
AggregateOffer variant
Use when a single product is available from multiple sellers at different prices — marketplace pages, comparison pages, competing listings for the same item. This is a drop-in replacement for the offers block above; everything outside offers stays the same.
"offers": {
"@type": "AggregateOffer",
"priceCurrency": "REQUIRED -- ISO 4217, e.g. USD",
"lowPrice": "REQUIRED -- lowest active offer price, numeric only, e.g. 19.99",
"highPrice": "OPTIONAL -- highest active offer price, numeric only",
"offerCount": "REQUIRED -- integer count of live offers",
"offers": [
{
"@type": "Offer",
"url": "REQUIRED -- direct URL to this individual seller listing",
"price": "REQUIRED -- numeric only",
"priceCurrency": "REQUIRED -- ISO 4217",
"availability": "REQUIRED -- https://schema.org/InStock",
"itemCondition": "REQUIRED -- https://schema.org/NewCondition",
"seller": { "@type": "Organization", "name": "REQUIRED -- seller name" }
}
]
}
Audience and intent variant
Standard Schema.org properties that give AI retrieval systems structured access to “who this is for” and “best for” statements otherwise buried in prose. Neither property triggers a Google rich result — add them alongside the core block, and only with values that appear in visible page content.
"audience": [
{ "@type": "Audience", "audienceType": "OPTIONAL -- intended buyer segment, e.g. Remote professionals" }
],
"additionalProperty": [
{ "@type": "PropertyValue", "name": "OPTIONAL -- visible attribute name, e.g. Best for", "value": "OPTIONAL -- visible attribute value" }
]
Field notes
- GTIN: use the narrowest applicable type —
gtin12for North American UPCs,gtin13for EAN-13,gtin8for short barcodes. Without a valid GTIN, Google can’t match the product and the listing may be suppressed.mpnis accepted as a substitute only when no GTIN exists, always paired withbrand. priceValidUntilis required for Shopping, not just recommended — a missing or expired date suppresses the listing; update it whenever price changes.- Feed alignment: price, availability, and GTIN must match your Merchant Center feed exactly — mismatches cause suppression regardless of markup validity.
- Omit
aggregateRatingentirely if the page has no reviews — never setreviewCount: 0. - Pages covering multiple variants (color, size, SKU) with a single schema block produce a validation error — use
hasVariantto link a parent Product node to child Product nodes, each with its own identifier and URL. - Don’t use
AggregateOfferon a single-seller page — use a plainOffer; Google indexes and surfaces them differently. Each child Product node underhasVariantshould carry its own plainOffer, not anAggregateOffer. - Apparel categories require
color,size,gender, andageGroup— omitting them in apparel-classified listings triggers a validation error.