Product Schema: Variants, Availability, Ratings
The rich results that drive ecommerce CTR — implemented without the pitfalls
Product schema is table-stakes for ecommerce SEO. Stars, prices, and availability visible in the SERP lift CTR 15-30% versus plain results. The implementation isn't complex — JSON-LD with a Product type — but the pitfalls are. Schema that claims features the visible page doesn't show triggers manual penalties. Variants generate duplicate-content concerns if handled wrong. Availability that doesn't match visible stock status gets your rich results suppressed.
This article covers the correct product schema structure, the variant-handling patterns, the availability accuracy problem, and the validation workflow that catches regressions before Google does.
The core Product schema
Minimum viable product schema:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Nike Pegasus 41 Running Shoe",
"image": [
"https://example.com/pegasus-41-1x1.jpg",
"https://example.com/pegasus-41-4x3.jpg",
"https://example.com/pegasus-41-16x9.jpg"
],
"description": "Road running shoe with Air Zoom cushioning. Built for daily training and longer runs.",
"sku": "NIKE-PEG-41-BLACK-10",
"mpn": "FD2722-010",
"brand": {
"@type": "Brand",
"name": "Nike"
},
"offers": {
"@type": "Offer",
"url": "https://example.com/running/nike-pegasus-41",
"priceCurrency": "EUR",
"price": "139.00",
"priceValidUntil": "2026-12-31",
"availability": "https://schema.org/InStock",
"itemCondition": "https://schema.org/NewCondition",
"seller": {
"@type": "Organization",
"name": "Example Store"
}
}
}
Fields that matter:
name— the product name as displayed on the page. Match exactly; don't add keyword-stuffing suffixes.image— array of 3 images minimum: 1:1 (square), 4:3, 16:9. Each should be at least 1200px on the long side. Different aspect ratios enable different SERP layouts.description— 160-300 characters, matches page description.skuandmpn— product identifiers. Helps Google distinguish your product listing from duplicates across the web.brand—Brandtype with name. Important for brand-query ranking.offers— the purchase offer. Required for price/availability rich results.
The Offers object in depth
Offers are where most schema bugs live. The required fields:
| Field | Values | Notes |
|---|---|---|
url |
Canonical URL for this specific offer | Usually the PDP URL |
priceCurrency |
ISO 4217 (EUR, USD, GBP) |
Match the currency shown on-page |
price |
Numeric value | No currency symbol; just the number |
priceValidUntil |
ISO 8601 date | When the offer expires |
availability |
Schema.org URL | InStock, OutOfStock, PreOrder, BackOrder |
itemCondition |
Schema.org URL | NewCondition, UsedCondition, RefurbishedCondition |
Availability values:
https://schema.org/InStock— product is availablehttps://schema.org/OutOfStock— not currently availablehttps://schema.org/PreOrder— available for pre-orderhttps://schema.org/BackOrder— backorderedhttps://schema.org/Discontinued— permanently unavailable
The availability value must match what users see on the page. Claiming InStock while the page says "Out of stock" triggers penalties.
priceValidUntil semantics:
Google wants a specific end date for the offer. Without it, rich results get suppressed. Common patterns:
- For stable pricing: end of the current year (
"2026-12-31") — acceptable. - For time-limited offers: the actual end date of the promotion.
- Don't use far-future dates like
"2099-12-31"— Google's systems may discount.
Variant handling
Variants (color, size, spec options) are the hardest product schema problem. Three patterns, each with trade-offs.
Pattern 1: One URL per product, variants in-page
User selects color/size from a dropdown on the PDP; URL doesn't change.
{
"@type": "Product",
"name": "Nike Pegasus 41",
"description": "...",
"image": [...],
"sku": "NIKE-PEG-41",
"brand": { "@type": "Brand", "name": "Nike" },
"offers": [
{
"@type": "Offer",
"sku": "NIKE-PEG-41-BLACK-10",
"price": "139.00",
"priceCurrency": "EUR",
"availability": "https://schema.org/InStock",
"itemOffered": {
"@type": "Product",
"name": "Nike Pegasus 41 - Black - Size 10"
}
},
{
"@type": "Offer",
"sku": "NIKE-PEG-41-WHITE-10",
"price": "139.00",
"priceCurrency": "EUR",
"availability": "https://schema.org/OutOfStock"
}
]
}
All variants as an array of Offers. Google shows price range if variants have different prices. Single URL indexed.
Pattern 2: One URL per variant with canonical
Each variant gets its own URL (/pegasus-41-black, /pegasus-41-white), all canonical to the parent product URL.
<!-- On /pegasus-41-black -->
<link rel="canonical" href="/pegasus-41">
Each variant URL has its own Product schema. Advantages: can target variant-specific queries ("nike pegasus 41 black"). Disadvantages: more URLs to manage.
Pattern 3: Hybrid (recommended for catalogs with differentiated variants)
- Variants with materially different content (different photos, different specs, different market positioning) get their own URL with full schema.
- Variants that are purely cosmetic (size only, for example) live under one URL with in-page selection.
This matches how users search: "nike pegasus 41 black" is a real query; "nike pegasus 41 size 9.5" is not.
AggregateRating (stars in the SERP)
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.6",
"reviewCount": "127",
"bestRating": "5",
"worstRating": "1"
}
Required for rich result eligibility: ratingValue + either reviewCount or ratingCount.
Critical rules:
- Reviews must be visible on the page. Schema claiming 127 reviews on a page with 0 visible reviews is a manual-action trigger.
- Ratings must reflect real user reviews, not aggregated from third parties without attribution.
bestRatingdefaults to 5 if omitted; include for clarity.
Fake or manufactured reviews violate Google's spam policies and can get your site delisted. Don't.
Review schema (individual reviews)
For displaying specific reviews on the PDP:
"review": [
{
"@type": "Review",
"reviewRating": {
"@type": "Rating",
"ratingValue": "5",
"bestRating": "5"
},
"author": {
"@type": "Person",
"name": "Jane Doe"
},
"datePublished": "2026-04-15",
"reviewBody": "Great fit, ran 300 miles without issues."
}
]
Google may display individual review stars in specific rich result layouts. Required: real reviews, real authors (even pseudonymous), real dates.
Common mistakes
Claiming stars on a page without visible reviews. Classic manual-action trigger. Schema must match visible content.
Stale priceValidUntil. Date in the past signals expired offer; rich results suppressed. Refresh periodically — CMS-level automation is the cleanest solution.
availability: InStock when the page says "Out of stock." Trust discount from Google's quality systems. Sync schema to real-time inventory. See out-of-stock SEO strategy for the full lifecycle (temporary stockouts vs discontinued vs seasonal).
Using the wrong currency code. € symbol in priceCurrency instead of EUR. Schema validators catch this; still common in hand-written schema.
Multiple conflicting Product schemas on one page. From plugins or theme layers. Google picks one (usually the first); the others confuse the parse. Consolidate to one canonical schema generator.
Schema generated in JavaScript-only. For SEO-critical schema, server-render in the initial HTML. See JavaScript SEO for the two-pass indexing implications.
Discontinued products without availability: Discontinued. Google keeps showing them as available, users land on dead pages. Mark discontinued correctly.
Validation workflow
Required for any template generating schema:
1. Unit tests in CI. For each template (product, category, etc.), test that the template outputs valid JSON-LD against a representative data set. Validate structure, required fields, proper URLs.
2. Rich Results Test post-deploy. For 3-5 critical pages, run the Google Rich Results Test after every deploy touching the schema template. Confirm eligibility for product rich results.
3. Weekly monitoring. GSC's Enhancements reports (→ Merchant listings, Products) show when Google last processed your schema and how many URLs are eligible. Drops in eligible-URL count indicate regressions.
4. Sample the fleet. For large catalogs, a random sample check every week. 20-50 random product URLs, run through automated validators, flag failures.
Migrating from Microdata or RDFa
Legacy schema implementations using Microdata (itemtype, itemprop attributes sprinkled in HTML) still work but are harder to maintain. Migrate to JSON-LD:
Before (Microdata):
<div itemscope itemtype="https://schema.org/Product">
<h1 itemprop="name">Pegasus 41</h1>
<meta itemprop="sku" content="NIKE-PEG-41-BLACK-10">
<div itemprop="offers" itemscope itemtype="https://schema.org/Offer">
<span itemprop="price">139.00</span>
</div>
</div>
After (JSON-LD):
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Pegasus 41",
"sku": "NIKE-PEG-41-BLACK-10",
"offers": {
"@type": "Offer",
"price": "139.00"
}
}
</script>
<h1>Pegasus 41</h1>
<span>€139.00</span>
JSON-LD wins: decoupled from markup, easier to generate programmatically, survives template changes cleanly.
Migrate one template at a time. Run in parallel (both formats) during transition to avoid brief schema gaps.
Frequently asked questions
How long after adding product schema do rich results appear?
Typically 1-4 weeks. Google needs to recrawl, parse, and re-evaluate rich result eligibility. Use the Rich Results Test to confirm eligibility immediately; wait for GSC to show actual impression data to confirm SERP display.
Do I need both Product schema and Offer schema?
Product schema with an offers field containing an Offer — yes. They're complementary, not alternatives. Product describes the item; Offer describes the purchase terms.
Should my manufacturer's description be in schema description?
No — manufacturer descriptions are typically duplicated across many retailers. Use your site's unique product description. See duplicate product content.
What if my product has variants with different prices?
Use an array of Offers (one per variant) or use AggregateOffer with lowPrice and highPrice. Google displays a price range in the SERP when appropriate.
Can I use product schema for digital products?
Yes. Same Product type. For digital goods, you may also want isDigitalDocument or SoftwareApplication types where applicable.
What to read next
- E-commerce SEO Playbook — product schema in the broader ecommerce picture.
- Structured data that moves rankings — the general schema strategy.
- Review schema markup — the adjacent review + aggregate rating patterns.
Related articles
Out-of-Stock Product Pages: 4 Strategies Compared
Most ecommerce sites handle out-of-stock products inconsistently, destroying seasonal rankings. The four viable strategies (keep with notice, 301 to category, 410 Gone, 404) each fit specific scenarios. Here's the decision tree and the reindexation implications.
Category Filters: UX vs SEO Trade-offs
Category filters are the UX feature with the most SEO footprint. Every filter selection is a potential URL. Most shouldn't be indexed, but the ones with real search intent should. The trade-off between UX flexibility and SEO cleanliness is worth deliberate design.
Breadcrumb Schema for E-commerce: The Full Implementation Guide
Breadcrumb schema appears in almost every SERP where an ecommerce site ranks. It's the simplest rich result to implement correctly and the one that most directly signals site hierarchy. Here's the implementation that works across category structures.