- Product schema has two flavors:
Merchant listingfor sellable products andProduct snippetfor editorial reviews. Pick based on whether you sell the product or review it. - Required for merchant listing:
name,image,offers(withprice,priceCurrency,availability). - Ship GTIN, MPN, brand, and SKU when you have them. These power Google Shopping eligibility and product disambiguation across the entire web.
- Use
ProductGroupfor variant products (size, color, material). Each variant is a Product nested under the group with a uniquesku. - Server-render Product schema for fast-changing fields like price and availability. JavaScript-injected schema is slower for Google to reliably read.
Chapter 1. Before you start
Product schema is the single most ROI-positive structured data type for ecommerce. It powers Google Shopping rich results, Merchant Center product feeds, price comparison snippets, and the product cards that increasingly appear in AI Overviews and ChatGPT responses. Get it right and you compete in the visual SERP; get it wrong and you're text-only.
- Confirm whether you sell the product or review it. Sellable = Merchant listing. Editorial review = Product snippet. Don't ship both on the same page.
- Gather identifiers per product: GTIN (UPC, EAN, ISBN), MPN, brand name, and SKU. Missing identifiers lower product visibility in Google Shopping.
- Have your shipping and returns policies documented as
MerchantReturnPolicyandShippingService. These are now required for many product rich result types. - Decide on server-side vs client-side rendering. Server-side is strongly recommended for price + availability; Google's docs explicitly warn about JS-injected schema for fast-changing fields.
availability field
being missing or stale (showing "InStock" when the variant was sold out), which made every
product on the site ineligible for Google Shopping rich results. The fix is a 1-line code
change in the product template; the impact compounds across every PDP.
Chapter 2. Should you ship a merchant listing or a product snippet?
Pick based on whether you sell the product or review it. Merchant listing is for stores selling the product; Product snippet is for editorial roundups and review sites covering products they don't sell. Shipping the wrong one (or both) is a Google structured-data policy violation.
| Criterion | Merchant listing | Product snippet |
|---|---|---|
| You sell the product | Yes | No |
| Use case | PDP on your ecommerce store | "Best toothbrushes 2026" editorial review |
Required: offers | Yes | No |
| Required: name, image | Yes | Yes |
Supports positiveNotes / negativeNotes | No | Yes (pros/cons reviews) |
| Rich result eligibility | Google Shopping cards, price snippets | Star ratings, review snippets |
| Self-serving review allowed | No | No (must be third-party site) |
The full split lives in Google's Product structured data documentation.
Chapter 3. Required and recommended properties
For a Merchant listing (your own ecommerce PDP), the required and recommended floor:
{
"@context": "https://schema.org",
"@type": "Product",
"@id": "https://www.example.com/products/example-product#product",
"name": "Example Product Name",
"description": "Short product description that matches the visible content.",
"image": [
"https://www.example.com/products/example-product/1x1.jpg",
"https://www.example.com/products/example-product/4x3.jpg",
"https://www.example.com/products/example-product/16x9.jpg"
],
"sku": "EX-001",
"gtin13": "0123456789012",
"mpn": "MFR-001",
"brand": { "@type": "Brand", "name": "Example Brand" },
"offers": {
"@type": "Offer",
"url": "https://www.example.com/products/example-product",
"priceCurrency": "USD",
"price": "49.99",
"availability": "https://schema.org/InStock",
"itemCondition": "https://schema.org/NewCondition",
"hasMerchantReturnPolicy": { "@id": "https://www.example.com/#return-policy" },
"shippingDetails": { "@id": "https://www.example.com/#shipping-service" }
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.7",
"reviewCount": "127"
}
}
The image array follows the same 1:1, 4:3, 16:9 pattern as Article schema. Aggregate rating is recommended but optional; if included, the rating value must match what's visible on the page. Reviews must be real customer reviews, not fabricated for SEO - faking them triggers manual actions.
Chapter 4. The Offer block
The offers block is what makes a Product schema eligible for shopping rich
results. It needs three fields at minimum: price (or
priceSpecification.price), priceCurrency (ISO 4217 code), and
availability (a Schema.org URL).
price: numeric string ("49.99"), not formatted ("$49.99"). Decimals always with a period, not a comma.priceCurrency: ISO 4217 three-letter code (USD,EUR,GBP).availability: full Schema.org URL likehttps://schema.org/InStock,OutOfStock,PreOrder,BackOrder, orDiscontinued.priceValidUntil: ISO 8601 date for sale prices. Optional but strongly recommended for time-limited offers.hasMerchantReturnPolicy+shippingDetails: increasingly required by Google Merchant Center for product rich results.
For sale prices, ship the current price in price and the strikethrough
original in a second Offer with priceType: "StrikethroughPrice". The combined
markup unlocks Google's discount-rich-result eligibility.
Chapter 5. GTIN, MPN, brand: the identifier triad
Product identifiers tell Google which physical product you're selling and let it disambiguate your listing from competitors selling the same SKU. The three core identifiers, in order of importance:
| Identifier | What it is | When to use |
|---|---|---|
gtin / gtin8 / gtin12 / gtin13 / gtin14 | Global Trade Item Number (UPC, EAN, JAN, ISBN) | Required for branded products in Merchant Center |
mpn | Manufacturer Part Number | When GTIN is unavailable (private label, custom) |
brand | Brand name as a Brand entity | Always, with very rare exceptions |
sku | Your internal stock-keeping unit | Always; helps Google differentiate variants |
For private-label or own-brand products without GTINs, ship mpn +
brand + sku as the identifier set. Google accepts this but ranks
identifierless products lower in Shopping than products with GTINs. If you're a reseller
selling third-party branded products, get the GTIN from the manufacturer; missing GTIN on
branded products disqualifies you from Merchant Center entirely.
Chapter 6. ProductGroup for variants
Use ProductGroup when a product is sold in size, color, material, or
pattern variants. Each variant is its own Product nested under the
group with a unique sku or gtin; the group has a
productGroupID that ties them together for Google.
{
"@context": "https://schema.org",
"@type": "ProductGroup",
"@id": "https://www.example.com/products/example-shirt#product-group",
"name": "Example Shirt",
"description": "Brand short-sleeve shirt in 3 colors and 5 sizes.",
"productGroupID": "PG-12345",
"variesBy": ["https://schema.org/color", "https://schema.org/size"],
"hasVariant": [
{
"@type": "Product",
"sku": "SH-RED-S",
"color": "Red",
"size": "S",
"offers": { "@type": "Offer", "price": "29.99", "priceCurrency": "USD", "availability": "https://schema.org/InStock" }
},
{
"@type": "Product",
"sku": "SH-RED-M",
"color": "Red",
"size": "M",
"offers": { "@type": "Offer", "price": "29.99", "priceCurrency": "USD", "availability": "https://schema.org/OutOfStock" }
}
]
}
Do not use AggregateOffer for variants; Google deprecated that approach in
favor of ProductGroup. Full variant guidance lives in
Google's
Product variants documentation.
Chapter 7. The breakages we see most often
Ranked by frequency across 47 ecommerce schema audits over the past 24 months:
- Missing or stale
availability: products showing "InStock" when sold out. Disqualifies from Shopping rich results. 28 of 47. - No GTIN on branded resold products: disqualifies from Merchant Center entirely. 22 of 47.
- JavaScript-injected schema for price and availability: Google's docs explicitly warn against this. 18 of 47.
AggregateOfferused for variants instead ofProductGroup. 14 of 47.- Self-serving
aggregateRatingbased on fake reviews: manual-action risk. 11 of 47. - Currency mismatch between display price and schema: revenue reports diverge. 9 of 47.
- Image array shipped as a single 1:1 image: rich result eligibility narrowed. 7 of 47.
We track Product schema integrity continuously through our Sentry product; the structured-data rule set catches every breakage above on running ecommerce sites.
FAQ
What's the difference between Product, Offer, and ProductGroup?
Product is the thing being sold. Offer is the price + availability
+ currency + condition tied to that Product. ProductGroup wraps multiple
variant Products together (size, color, material). For a single-variant product, ship
Product + Offer. For a multi-variant product, ship ProductGroup containing one Product +
Offer per variant.
What's strictly required for a Google Merchant Listing?
Per Google: name, image, and offers (with
price, priceCurrency, and availability inside).
Everything else is recommended. The recommended floor includes sku,
gtin, brand, description, and the
hasMerchantReturnPolicy / shippingDetails blocks.
Do I need GTIN if my products are private label?
No. GTINs only exist for products sold across multiple retailers under a common
identifier. For private-label or own-brand products, ship mpn +
brand + sku as the identifier set. Google accepts this but
ranks identifierless products slightly lower in Shopping than products with GTINs.
How do I handle variants?
Use ProductGroup with each variant as a nested Product under
hasVariant. Each variant needs a unique sku; the group needs
a stable productGroupID. List the variant dimensions in
variesBy. Avoid AggregateOffer - Google deprecated that pattern
in favor of ProductGroup.
Can I JavaScript-inject Product schema?
You can, but Google explicitly warns against it for fast-changing fields like price and availability: "dynamically-generated markup can make Shopping crawls less frequent and less reliable." Server-render Product schema whenever possible. Reserve JS injection for fields that don't change frequently or for sites where server rendering isn't feasible.
Where does Product schema go on the page?
On the product detail page only, inside a <script type="application/ld+json">
tag. Do not ship Product schema on category pages, search results, or homepages. Each PDP
gets exactly one Product schema block matching the product on that page.
References
- Schema.org. "Product." schema.org/Product
- Google Search Central. "Product (Product, Review, Offer) structured data." developers.google.com/search/docs/appearance/structured-data/product
- Google Search Central. "Product variants." developers.google.com/search/docs/appearance/structured-data/product-variants
- Schema.org. "ProductGroup." schema.org/ProductGroup
- Google Merchant Center Help. "Required product attributes." support.google.com/merchants/answer/7052112
- Schema.org. "Schema Markup Validator." validator.schema.org
- Google. "Rich Results Test." search.google.com/test/rich-results