Product variant schema generator
Mark up a product that comes in several sizes or colours as one ProductGroup with a Product for each variant, the structure Google documents for product variants.
All Google-required properties present. That makes the page eligible, not guaranteed. Google's docs
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "ProductGroup",
"name": "Trailhead 2 waterproof hiking boot",
"description": "Full-grain leather mid boot with a waterproof membrane.",
"url": "https://example.com/p/trailhead-2",
"brand": {
"@type": "Brand",
"name": "Example Outfitters"
},
"productGroupID": "TH2",
"variesBy": [
"https://schema.org/size",
"https://schema.org/color"
],
"hasVariant": [
{
"@type": "Product",
"sku": "TH2-BRN-42",
"name": "Trailhead 2 waterproof hiking boot – Brown – 42",
"image": "https://example.com/img/th2-brown.jpg",
"size": "42",
"color": "Brown",
"inProductGroupWithID": "TH2",
"offers": {
"@type": "Offer",
"price": 149,
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"url": "https://example.com/p/trailhead-2?sku=TH2-BRN-42"
}
},
{
"@type": "Product",
"sku": "TH2-BRN-43",
"name": "Trailhead 2 waterproof hiking boot – Brown – 43",
"image": "https://example.com/img/th2-brown.jpg",
"size": "43",
"color": "Brown",
"inProductGroupWithID": "TH2",
"offers": {
"@type": "Offer",
"price": 149,
"priceCurrency": "USD",
"availability": "https://schema.org/OutOfStock",
"url": "https://example.com/p/trailhead-2?sku=TH2-BRN-43"
}
},
{
"@type": "Product",
"sku": "TH2-BLK-42",
"name": "Trailhead 2 waterproof hiking boot – Black – 42",
"image": "https://example.com/img/th2-black.jpg",
"size": "42",
"color": "Black",
"inProductGroupWithID": "TH2",
"offers": {
"@type": "Offer",
"price": 155,
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"url": "https://example.com/p/trailhead-2?sku=TH2-BLK-42"
}
}
]
}
</script>When to use ProductGroup markup
- A product page where the visitor picks a size, colour or material.
- Shops that want each variant's price and stock understood by Google.
- Not for unrelated products on one page (use separate Product pages).
Getting it right
- ProductGroup only requires name; Google recommends brand, description, hasVariant, productGroupID, url and variesBy.
- Each variant is a Product and should meet product snippet or merchant listing requirements on its own: name, image and an Offer with price and currency.
- Repeat the parent ID in each variant's inProductGroupWithID.
- Give each variant a distinct URL (e.g. a ?sku= parameter) if your page supports selecting it by URL.
Source: Google Search Central, Product variants structured data documentation, and schema.org/ProductGroup.
Google's property list
| Property | Google says |
|---|---|
name | required |
aggregateRating | recommended |
brand | recommended |
brand.name | recommended |
description | recommended |
hasAdultConsideration | recommended |
hasVariant | recommended |
productGroupID | recommended |
review | recommended |
url | recommended |
variesBy | recommended |
Example output
{
"@context": "https://schema.org",
"@type": "ProductGroup",
"name": "Trailhead 2 waterproof hiking boot",
"description": "Full-grain leather mid boot with a waterproof membrane.",
"url": "https://example.com/p/trailhead-2",
"brand": {
"@type": "Brand",
"name": "Example Outfitters"
},
"productGroupID": "TH2",
"variesBy": [
"https://schema.org/size",
"https://schema.org/color"
],
"hasVariant": [
{
"@type": "Product",
"sku": "TH2-BRN-42",
"name": "Trailhead 2 waterproof hiking boot – Brown – 42",
"image": "https://example.com/img/th2-brown.jpg",
"size": "42",
"color": "Brown",
"inProductGroupWithID": "TH2",
"offers": {
"@type": "Offer",
"price": 149,
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"url": "https://example.com/p/trailhead-2?sku=TH2-BRN-42"
}
},
{
"@type": "Product",
"sku": "TH2-BRN-43",
"name": "Trailhead 2 waterproof hiking boot – Brown – 43",
"image": "https://example.com/img/th2-brown.jpg",
"size": "43",
"color": "Brown",
"inProductGroupWithID": "TH2",
"offers": {
"@type": "Offer",
"price": 149,
"priceCurrency": "USD",
"availability": "https://schema.org/OutOfStock",
"url": "https://example.com/p/trailhead-2?sku=TH2-BRN-43"
}
},
{
"@type": "Product",
"sku": "TH2-BLK-42",
"name": "Trailhead 2 waterproof hiking boot – Black – 42",
"image": "https://example.com/img/th2-black.jpg",
"size": "42",
"color": "Black",
"inProductGroupWithID": "TH2",
"offers": {
"@type": "Offer",
"price": 155,
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"url": "https://example.com/p/trailhead-2?sku=TH2-BLK-42"
}
}
]
}Product Variants schema questions
Do I still need Product markup if I use ProductGroup?
Yes. ProductGroup is the parent; each entry in hasVariant is a Product with its own offer. The generator builds both.
What values does variesBy take?
Google lists schema.org property URLs such as https://schema.org/size, https://schema.org/color, https://schema.org/material and https://schema.org/pattern, plus suggestedAge and suggestedGender.
Should every size have its own URL?
Google recommends that each variant be selectable by a distinct URL where possible, so a link can open the page with that variant chosen.