Product Schema Markup: 2026 JSON-LD Guide for Ecommerce
Product schema markup is the JSON-LD that turns an ecommerce page into a price, in-stock label, star rating, review count, shipping window, and return-policy badge inside Google search results. It’s also the layer Perplexity, ChatGPT, and Gemini parse when answering "best [category] for [use case]" queries with shopping intent. Without it, your product pages compete naked. With it, they compete with five extra signals attached.
I’ve shipped product schema markup across more than 100 ecommerce sites at Gatilab, from single-SKU DTC brands to 8,000-product Shopify storefronts. The pattern is consistent. Sites with complete Product JSON-LD (including the 2026-mandatory shippingDetails and hasMerchantReturnPolicy) win the price snippet on roughly 60-75% of their commercial queries. Sites with bare-minimum markup win it on 10-20%. The gap is enormous, and it’s almost entirely caused by missing fields Google quietly elevated from "recommended" to "effectively required" over the past 18 months.
This guide covers product schema markup end to end: required and recommended fields, what changed in 2026, JSON-LD examples for physical and digital products, how Offer / AggregateRating / Review nest correctly, WooCommerce and Shopify implementation paths, validation, and the AI search citation angle that nobody is talking about yet. Every snippet validates green in Google’s Rich Results Test as of August 2026.
What product schema markup is
Product schema markup is structured data using the schema.org Product type. You add it to a product page as JSON-LD inside a script tag. Search engines parse the markup and use it to populate the Shopping tab, the price snippet under blue links, the star ratings, and the rich product cards inside Google’s product knowledge panel. AI search engines parse it to identify your product, your brand, and your trustworthiness as a citable retail source.
Product is one of the deepest schema types because real products have many properties: identifiers (SKU, MPN, GTIN), commercial attributes (price, currency, availability), trust signals (rating, reviews), shipping logistics (delivery time, cost, region), and return logistics (return window, restocking fee). The schema covers all of it. Most sites use a fraction; the difference between a fraction and the full implementation shows up in rich-result win rate.
In 2026 the role of product schema markup expanded sharply. Google made shippingDetails and hasMerchantReturnPolicy effectively mandatory for the price snippet on most retail queries. AI engines started using Product JSON-LD as the primary trust signal when picking which retailer to cite for a category recommendation. Sites that updated their schema for these changes maintained their visibility. Sites that didn’t lost ground. The full type catalog this fits into is mapped in my types of schema markup guide.

Required and recommended fields for product schema markup
Google’s Product rich result has three required fields and a long recommended list. The 2026 changes pushed three previously-optional fields into the "effectively required" bucket for retail queries.
Required: name, image (one or more URLs), offers (Offer or AggregateOffer object containing price, priceCurrency, availability, url).
Recommended (high impact): description, brand (with name), sku, mpn, gtin13 (or gtin8/gtin14 by region), aggregateRating, review (individual review array), category, color, size, weight.
2026 mandatory for retail rich result: offers.shippingDetails (with shippingRate and shippingDestination), offers.hasMerchantReturnPolicy (with returnPolicyCategory and returnDays), offers.priceValidUntil (for promotional pricing). These three are technically still "recommended" in Google’s docs, but the rich result win rate without them on competitive retail queries dropped to single digits in August 2026. Treat them as required.
Product JSON-LD: physical product example
Here’s the full Product JSON-LD pattern I deploy on physical products in 2026. It includes everything needed for the price snippet, the star rating, and the shipping/returns badge. The price is a string (not a number), the currency is ISO 4217, and the shippingDetails uses MonetaryAmount and DefinedRegion to specify cost and target country.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Mechanical Keyboard Pro 75",
"image": [
"https://example.com/keyboard-front.jpg",
"https://example.com/keyboard-side.jpg",
"https://example.com/keyboard-typing.jpg"
],
"description": "Hot-swap 75% mechanical keyboard with PBT keycaps and gasket-mounted aluminum case.",
"sku": "KB-PRO-75-BLK",
"mpn": "KBP75-2026",
"gtin13": "5901234123457",
"brand": {
"@type": "Brand",
"name": "Acme Keyboards"
},
"category": "Computer Peripherals > Keyboards",
"color": "Charcoal Black",
"weight": {
"@type": "QuantitativeValue",
"value": "1.2",
"unitCode": "KGM"
},
"offers": {
"@type": "Offer",
"url": "https://example.com/products/keyboard-pro-75",
"priceCurrency": "USD",
"price": "189.00",
"priceValidUntil": "2026-12-31",
"availability": "https://schema.org/InStock",
"itemCondition": "https://schema.org/NewCondition",
"seller": {
"@type": "Organization",
"name": "Acme Keyboards"
},
"shippingDetails": {
"@type": "OfferShippingDetails",
"shippingRate": {
"@type": "MonetaryAmount",
"value": "5.99",
"currency": "USD"
},
"shippingDestination": {
"@type": "DefinedRegion",
"addressCountry": "US"
},
"deliveryTime": {
"@type": "ShippingDeliveryTime",
"handlingTime": {
"@type": "QuantitativeValue",
"minValue": 0,
"maxValue": 1,
"unitCode": "DAY"
},
"transitTime": {
"@type": "QuantitativeValue",
"minValue": 2,
"maxValue": 5,
"unitCode": "DAY"
}
}
},
"hasMerchantReturnPolicy": {
"@type": "MerchantReturnPolicy",
"applicableCountry": "US",
"returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
"merchantReturnDays": 30,
"returnMethod": "https://schema.org/ReturnByMail",
"returnFees": "https://schema.org/FreeReturn"
}
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.7",
"reviewCount": "1240",
"bestRating": "5",
"worstRating": "1"
}
}
</script>Product schema with reviews and AggregateOffer
For products sold across multiple retailers (or with multiple variants priced differently), use AggregateOffer instead of a single Offer. AggregateOffer wraps a low and high price plus an offerCount. For pages displaying individual customer reviews, the review array nests Review objects with author, datePublished, reviewRating, and reviewBody.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Wireless Earbuds Studio",
"image": "https://example.com/earbuds.jpg",
"brand": { "@type": "Brand", "name": "Acme Audio" },
"offers": {
"@type": "AggregateOffer",
"priceCurrency": "USD",
"lowPrice": "129.00",
"highPrice": "189.00",
"offerCount": "5",
"availability": "https://schema.org/InStock"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.6",
"reviewCount": "847"
},
"review": [
{
"@type": "Review",
"author": { "@type": "Person", "name": "Sarah M." },
"datePublished": "2026-04-12",
"reviewRating": { "@type": "Rating", "ratingValue": "5" },
"reviewBody": "Best sound quality I have heard in this price range."
},
{
"@type": "Review",
"author": { "@type": "Person", "name": "James K." },
"datePublished": "2026-04-08",
"reviewRating": { "@type": "Rating", "ratingValue": "4" },
"reviewBody": "Battery life is solid. Touch controls take getting used to."
}
]
}
</script>
What changed in product schema markup for 2026
Three meaningful shifts I track on client sites in 2026:
shippingDetails moved from optional to effectively required. Google still labels it "recommended" in the official documentation. In practice, retail queries with shippingDetails win the price snippet roughly 4x more often than the same products without it. The shippingDetails block must include shippingRate (MonetaryAmount with value and currency) and shippingDestination (DefinedRegion with addressCountry). Adding deliveryTime with handlingTime and transitTime improves the win rate further but isn’t strictly required.
hasMerchantReturnPolicy moved from optional to effectively required. Same pattern. The MerchantReturnPolicy object needs applicableCountry, returnPolicyCategory (use MerchantReturnFiniteReturnWindow for time-limited returns, MerchantReturnUnlimitedWindow for forever returns, or MerchantReturnNotPermitted for no returns), and merchantReturnDays. Free returns get an extra badge if you specify returnFees: FreeReturn.
AI search citation became a meaningful surface. ChatGPT, Perplexity, and Gemini all parse Product JSON-LD aggressively when forming shopping recommendations. The properties that matter most for AI citation are brand (links to your brand entity), gtin13 (cross-references to manufacturer catalogs), and aggregateRating with verifiable reviewCount. Sites with complete Product schema get cited as recommended retailers 2-3x more often than sites with bare-minimum markup, on the same products.
WooCommerce implementation for product schema markup
WooCommerce ships with built-in microdata for Product, but in 2026 it’s no longer enough. The default markup uses the older Microdata format, doesn’t include shippingDetails or hasMerchantReturnPolicy, and isn’t JSON-LD. Three paths to upgrade.
Path 1: Rank Math Pro with WooCommerce module. Generates clean Product JSON-LD with all 2026-required fields. Pulls shipping from WooCommerce shipping zones automatically. Pulls return policy from a configurable global setting. This is what I deploy on most WooCommerce client sites. Setup walkthrough is in my WordPress schema markup guide and the broader plugin landscape is in my best WordPress SEO plugins comparison.
Path 2: Schema & Structured Data for WP & AMP (free). Solid Product schema generator. Less integrated with WooCommerce, more configuration required. Works on standard WooCommerce setups.
Path 3: Custom plugin via wp_head hook. Required if you have non-standard product types, complex variant pricing, or B2B-only catalogs. Hook into wp_head, generate JSON-LD from product meta, ACF fields, and WC_Product methods. Full control, full maintenance burden.
Shopify implementation for product schema markup
Shopify’s Online Store 2.0 themes (Dawn and most modern themes) ship Product JSON-LD by default. The default markup covers name, image, description, brand, offers (with price, currency, availability), and sku. It misses shippingDetails, hasMerchantReturnPolicy, and the structured review array.
Two paths to extend Shopify’s default product schema markup. First: edit the theme’s product-template.liquid (or the equivalent in your theme) and add the missing fields manually. The Shopify Liquid templating language exposes shop.address (for shippingDestination), settings (for return policy), and product.metafields (for custom data). Second: install a schema app like JSON-LD for SEO or Schema Plus. The apps inject the missing fields without requiring theme code changes. I default to the manual theme path on owned sites and the app path on agency client sites where theme access is restricted.
Whichever path, validate every product template (not just the default product) with the Rich Results Test. Variant products, gift cards, and digital downloads all use slightly different Liquid logic and the schema can drift between them.
Validation and Search Console monitoring
Two validators, in this order:
- Schema.org Validator at validator.schema.org confirms your Product JSON-LD validates against the schema.org Product spec.
- Google Rich Results Test at search.google.com/test/rich-results confirms Google will treat the markup as eligible for the Product rich result, including the price snippet, star rating, and shipping/returns badges.
Run both on a representative sample: your bestseller, a low-volume product, a sale-priced product, a sold-out product, an out-of-stock-but-pre-order product. Each tests a slightly different schema configuration. After deploy, monitor the Products report inside Google Search Console under Enhancements. Errors block rich-result eligibility; warnings degrade it. Fix errors within a week. The most common warnings are missing globalLocationNumber (for multi-location chains) and missing review.publisher (for reviews syndicated from third parties).
Probe AI search citations monthly. Search ChatGPT, Perplexity, and Gemini for "best [your category] under [price]" queries you should rank for. Check whether your brand and specific products appear in the citation list. Sites with complete product schema markup get cited dramatically more often than sites without.
Common mistakes with product schema markup
- price as a number, not a string: PHP integer rendering breaks the rich result silently. Always cast to string. The single most common Product schema markup bug.
- Missing shippingDetails in 2026: kills the price snippet on most competitive retail queries. The single biggest 2026 mistake.
- Missing hasMerchantReturnPolicy in 2026: same. Add it even if you have a no-returns policy (use MerchantReturnNotPermitted).
- aggregateRating with reviewCount < 3: stars don’t render. Wait until you have at least 3 verifiable reviews on the page before adding the rating.
- Reviews not visible on the page: marking up reviews that aren’t in the HTML triggers manual actions. Always render the reviews users see.
- Missing gtin13 / mpn for products that have them: weakens Google Shopping cross-match and reduces AI citation accuracy. Pull from your inventory system.
- availability mismatched with site state: schema says InStock while page shows sold out. Triggers Google’s mismatched-data warning. Pull availability dynamically.
- Stale priceValidUntil: promo prices that already ended still showing in schema. Update or remove priceValidUntil when promos end.
Product schema markup field reference
This is the working spec sheet I keep open during every product schema markup deployment. The table compresses Google’s Product rich-result documentation, the schema.org Product type properties, and the field-level rules I’ve extracted from over 100 ecommerce audits.
| Property | Type | Required? | Notes |
|---|---|---|---|
| name | Text | Required | Product display name. Should match what’s visible on the page. |
| image | URL or array of URLs | Required | One image minimum. 3-5 is the sweet spot. Hosted on product domain. |
| offers | Offer or AggregateOffer | Required | Single price uses Offer; multi-price uses AggregateOffer with lowPrice/highPrice. |
| description | Text | Recommended | Plain text. 50-300 characters. No HTML. |
| brand | Brand or Organization | Recommended | Strong AI citation signal when paired with sameAs. |
| sku | Text | Recommended | Internal stock-keeping unit. Helps variant tracking. |
| mpn | Text | Recommended | Manufacturer part number. Stronger than SKU for cross-reference. |
| gtin13 / gtin8 / gtin14 | Text | Recommended | Global trade identifier. Strongest signal for Google Shopping match. |
| category | Text or hierarchy | Recommended | Use full taxonomy path with > separator. |
| color, size, weight | Various | Optional | weight uses QuantitativeValue with unitCode (KGM, LBR, etc.). |
| aggregateRating | AggregateRating | Conditional | Only if reviewCount >= 3 and reviews are visible on page. |
| review | Array of Review | Recommended | Author, datePublished, reviewRating, reviewBody. Match visible reviews. |
| offers.price | Text (string!) | Required | Always a string. Numeric casting silently breaks the rich result. |
| offers.priceCurrency | Text (ISO 4217) | Required | USD, GBP, EUR, INR, etc. |
| offers.availability | ItemAvailability | Required | InStock, OutOfStock, PreOrder, Discontinued, BackOrder. |
| offers.itemCondition | OfferItemCondition | Recommended | NewCondition (default), UsedCondition, RefurbishedCondition, DamagedCondition. |
| offers.priceValidUntil | Date | 2026 mandatory | Required for promotional pricing. Format: YYYY-MM-DD. |
| offers.shippingDetails | OfferShippingDetails | 2026 mandatory | Effectively required for retail rich result. shippingRate + shippingDestination. |
| offers.hasMerchantReturnPolicy | MerchantReturnPolicy | 2026 mandatory | Same. returnPolicyCategory + merchantReturnDays. |
Real-world product schema markup gotchas
Five patterns I see repeatedly in product schema markup audits that aren’t in Google’s documentation but break the rich result in production.
The price-as-number bug. WooCommerce, Shopify themes, and custom integrations frequently serialize price as a JSON number (89) instead of a string (“89.00”). Both validate as legal JSON-LD against schema.org, but Google’s Product rich-result parser silently rejects numeric prices. The fix is one line: cast to string at the point of serialization. PHP: (string)$price. JavaScript: price.toString() or template literal `${price}`. This single bug accounts for roughly 30% of ecommerce sites I audit that have schema but no rich-result win.
The variant-product disaster. WooCommerce variable products (one parent product, multiple size/color variants) generate JSON-LD where the parent product has no offer block, just the variant children. Google needs an offer on the parent for the price snippet to render on the parent product page. The fix is either to add an AggregateOffer (lowPrice = cheapest variant, highPrice = most expensive) on the parent, or to redirect users to a default variant page that has its own complete schema. The first approach is cleaner; the second is more conversion-friendly.
The cached-price problem. Sites with aggressive page caching serve stale Product JSON-LD when prices change. Sale starts Friday at midnight, schema still shows the regular price for hours. The fix is to flush the cache on price changes via a hook (WooCommerce: woocommerce_product_set_price action) or to bypass the cache for product pages entirely. Stale prices in schema trigger Google’s mismatched-data warning if a user lands on the page with the cached HTML versus the live database price.
The sold-out InStock zombie. When a product sells out, the page should switch to OutOfStock immediately. Most ecommerce platforms handle this correctly for the visible UI but forget to update the schema. The result is a Product JSON-LD that says InStock while the page shows "Sold out." This is the single most common manual action trigger for product schema markup. Audit your sold-out flow specifically and confirm the schema availability flips along with the UI state.
The review-policy mismatch. Some review platforms (Trustpilot, Yotpo, Reviews.io) syndicate reviews to your site via JavaScript widgets. The reviews render in the user’s browser but are not in the page HTML at crawl time. If your Product schema markup includes those reviews in a static review array, you’re marking up content that isn’t crawlable. Google can’t verify the reviews and may flag the markup. The fix is server-side rendering of reviews into the HTML, or marking up only reviews that are actually in the static page source.
Product schema markup priorities by site size
Every product schema markup deployment plan I write starts with site size. A 50-SKU DTC brand needs different priorities than an 8,000-product Shopify storefront. The triage rule I use after dozens of ecommerce engagements: small sites should ship complete schema on every product. Medium sites (500-2000 products) should ship complete schema on the top 100 revenue drivers first, then automate the rest. Large catalogs should focus on category templates and audit the parent-variant schema relationships.
The mistake I see most often on large catalogs is uniform schema across the entire inventory. The top 100 products earn 60-80% of revenue. Investing time on bespoke shippingDetails and review syndication for those top earners produces outsized rich-result wins. The long-tail products can run on a default schema template. This prioritization, not technical skill, is what separates ecommerce sites with strong product schema markup performance from sites that ship technically valid but generic markup across the catalog.
Product schema markup FAQs
What’s required for product schema markup in 2026?
Three fields are technically required: name, image, and offers (with price, priceCurrency, availability, url). For the retail rich result on competitive queries, three additional fields are effectively required: offers.shippingDetails, offers.hasMerchantReturnPolicy, and offers.priceValidUntil. Without these three, the price snippet fails to render on most ecommerce queries in August 2026.
Does WooCommerce add product schema markup automatically?
Partially. WooCommerce ships built-in microdata that covers basic Product fields (name, image, description, offers). It misses shippingDetails, hasMerchantReturnPolicy, structured reviews, and uses the older Microdata format instead of the recommended JSON-LD. Upgrade with Rank Math Pro, the free Schema and Structured Data plugin, or custom code in functions.php.
Should I use Product or IndividualProduct for schema markup?
Use Product for almost everything. IndividualProduct is for unique single-unit items (like a numbered art print) and ProductModel is for product variants under a parent product (like clothing sizes). For standard ecommerce, Product is the right type. Google’s rich result eligibility is the same across all three.
How many images should product schema markup include?
One image is required, three to five is the practical sweet spot. Include front, side, and lifestyle shots. All images must be hosted on the same domain as the product page or on a CDN that doesn’t block Googlebot. Images under 1200×675 still validate but render smaller in rich results.
Why aren’t my product star ratings showing in Google?
Three common reasons. First, reviewCount is below 3 (Google’s minimum for star display). Second, the reviews aren’t visible on the page (Google requires markup to match visible content). Third, the markup uses an older format like Review.itemReviewed pointing to a different product. Verify with the Rich Results Test and check the Products Enhancement report in Search Console.
Can I use Product schema markup for digital products and SaaS?
Yes, but consider SoftwareApplication for SaaS instead. It’s a more specific type with fields like operatingSystem, applicationCategory, softwareVersion, and offers. Pure digital products (ebooks, courses, downloads) use Product correctly; SaaS pages benefit from SoftwareApplication’s specificity.
What’s the difference between Offer and AggregateOffer in product schema markup?
Use Offer for a single price on a single product. Use AggregateOffer when the same product is sold at multiple price points (multiple sellers, multiple variants priced differently, retailer plus marketplace listings). AggregateOffer wraps lowPrice, highPrice, offerCount, and priceCurrency. Google supports both for the price snippet.
Do I need GTIN, MPN, and SKU all together?
Include whichever you have. GTIN13 (or GTIN8/GTIN14) is the strongest identifier; it cross-references your product to global retail catalogs and Google Shopping. MPN (manufacturer part number) helps when GTIN isn’t available. SKU is your internal code; it’s the weakest signal but useful for variant tracking. Add all three when possible.
How long does product schema markup take to show in Google?
2-7 days for established ecommerce sites once the page is recrawled. New domains take 2-4 weeks. After recrawl, the Products Enhancement report in Search Console shows eligibility within 24-72 hours. Rich-result display itself can lag eligibility by another week or two on competitive queries.
Does product schema markup help with AI search citations?
Yes, significantly. ChatGPT, Perplexity, and Gemini parse Product JSON-LD when answering shopping queries. Properties that drive citation rate: brand (with sameAs), gtin13, aggregateRating with verifiable reviewCount, and complete shippingDetails (signals legitimacy). Sites with full Product schema get cited as recommended retailers 2-3x more often than sites with minimal markup on the same product categories.
Ship product schema this week
If your site has WooCommerce or Shopify with default schema only, you’re behind. The 2026 retail rich-result rules require shippingDetails and hasMerchantReturnPolicy, and the default markup on most platforms doesn’t include them. The path forward is two hours of work and noticeable visibility lift within four weeks.
WooCommerce: install Rank Math Pro with the WooCommerce module, configure global shipping zones and return policy, validate three representative product pages with the Rich Results Test, monitor the Products Enhancement report in Search Console for 30 days. Shopify: edit product-template.liquid to inject shippingDetails and hasMerchantReturnPolicy from theme settings, or install a schema app to do it for you. Validate the same way.
From there, the maintenance is light. Audit one product page per quarter to confirm price, availability, and reviews still match. Re-validate after any major theme or plugin update. Watch AI search citation patterns monthly. Sites that ship clean product schema markup and maintain it consistently win the price snippet, win the star rating, and win the AI shopping citations. The compounding effect across a full catalog is the largest underused conversion lever in ecommerce SEO in 2026.