Schema.org Product in JSON-LD: E-commerce Guide 2026
Product JSON-LD enables Google rich results like stars, price, and stock status. Here’s the full 2026 implementation and errors to avoid.

Schema.org Product in JSON-LD: E-commerce Guide 2026
You’ve probably seen those Google results where a product page shows stars, price, and “In stock” directly under the title. That’s a rich result, and it’s what a properly implemented schema.org Product triggers. Sites that get them often see CTR increase by 15 to 40% at the same ranking position compared with results without rich results.
In 2026, implementation through JSON-LD is the official method recommended by Google. Here is the complete, testable, production-ready version.
Why JSON-LD instead of Microdata or RDFa
Three formats can add schema.org to a web page: Microdata (directly in the HTML), RDFa (HTML5 attributes), and JSON-LD (a separate structured data block).
Google has recommended JSON-LD since 2015, and by 2026 it has become the de facto standard. Reasons:
- Data/presentation separation: JSON-LD lives in a
<script type="application/ld+json">inside the<head>, independently from the visible HTML - Easier to generate: one JSON block per page, easy to maintain
- No conflict with your theme: no need to modify the HTML structure of templates
- Better compatibility with modern frameworks (Next.js, Nuxt, etc.)
Microdata is still readable by Google but is no longer recommended for new implementations.
The 7 required (or recommended) fields for a Product
Here is a minimal Product JSON-LD that passes Google tests and enables rich results:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Men's leather Derby shoe",
"description": "Derby shoe in Italian leather, hand-finished, available in sizes 38 to 46.",
"image": [
"https://example.com/products/derby-01.jpg",
"https://example.com/products/derby-02.jpg",
"https://example.com/products/derby-03.jpg"
],
"sku": "DERBY-BLK-44",
"brand": {
"@type": "Brand",
"name": "Atelier Maison"
},
"offers": {
"@type": "Offer",
"url": "https://example.com/products/derby-cuir-homme",
"priceCurrency": "EUR",
"price": "149.00",
"availability": "https://schema.org/InStock",
"itemCondition": "https://schema.org/NewCondition"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.7",
"reviewCount": "38"
}
}
Breakdown:
@contextand@type— declare that this is a schema.org Productname— the product name (≤100 chars recommended)description— short description (150-300 chars)image— array of image URLs (minimum 1, ideally 3-6 in high resolution)sku— unique product identifier (required for rich results)brand— product brandoffers— pricing and availability structure (critical)aggregateRating— average rating if you have reviews (triggers stars in the SERP)
Offer and AggregateRating: critical details
Offer
This is the most sensitive part. Four rules to follow:
priceCurrency in ISO 4217: "EUR", "USD", "GBP"… not "€", "$", or "£". This is a common error that causes rich results to fail.
price as a string, not a number: "149.00" not 149.00. Google accepts both in 2026, but the guidelines recommend a string.
availability as a full schema.org URL:
https://schema.org/InStock→ in stockhttps://schema.org/OutOfStock→ out of stockhttps://schema.org/PreOrder→ preorderhttps://schema.org/BackOrder→ special order with lead time
priceValidUntil (optional but recommended): price expiration date in ISO 8601 format ("2026-12-31"). Google uses it to detect outdated prices.
AggregateRating
This triggers stars in the SERP. Requirements:
ratingValuebetween 1 and 5reviewCount: minimum 1, but Google recommends 3+ for display- The matching reviews must be visible on the page — faking AggregateRating with nonexistent reviews can lead to a manual penalty
Tip: if you have few reviews, display them on your page through a widget (Yotpo, Judge.me, Trustpilot) and pull the count + average rating from their API for the JSON-LD.
Test with Rich Results Test
Before pushing to production, test every product page template with Google’s Rich Results Test.
It checks:
- Valid JSON syntax
- All required fields present
- Values in expected formats (URLs, dates, currencies)
- Eligibility for rich results
Common errors reported:
"availability" expected schema.org URL→ you used "In stock" instead of the schema.org URL"priceCurrency" invalid→ currency is not ISO 4217Missing field "sku"→ no SKU in the OfferMultiple products in single offer→ you tried to put multiple products in one JSON-LD block
Once the test passes, Google Search Console reports performance and errors over 2-4 weeks through Enhancements → Products.
Implementation by platform
Shopify
Since 2023, Shopify automatically generates Product schema on product pages if you use an official theme. The problem: the default schema is often incomplete (no AggregateRating, no brand).
For a complete schema:
- Edit your theme: Online Store → Themes → Edit code
- Open
snippets/product-structured-data.liquidorsections/main-product.liquid - Add the missing fields or replace it with a custom template
Alternative: install an app like SEO JSON-LD Schema or Smart SEO that manages schema across the full catalog on its own.
WooCommerce
WooCommerce also generates default schema starting from v5+, but it is incomplete. Recommended plugins to complete it:
- RankMath (free): handles Product schema with Offer and AggregateRating
- Yoast WooCommerce SEO (paid): enriches Yoast’s default schema
- WP SEO Structured Data Schema: more granularity if you want to customize by template
Next.js / headless
If you use a custom frontend, inject the JSON-LD into the <head> through an SSR component:
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(productSchema)
}}
/>
Warning: generating JSON-LD client-side (through useEffect) does not work for SEO — Google crawls server-rendered output. Make sure the JSON-LD is present in the initial HTML returned by the server.
Typical mistakes to avoid
Contradictions between the visible page and the JSON-LD. If the page shows “In stock” but the JSON-LD says OutOfStock, Google ignores the JSON-LD. Sync both to the same data source.
Different price in JSON-LD and on the page. Same logic: Google detects the mismatch and ignores the rich result.
Multiple Product objects in the same <script>. Only one @type: Product per script. If you have variants, use @type: ProductGroup with hasVariant: [...] to link them.
Images not accessible. Image URLs must be public, not behind a login. Test each URL with curl to confirm it returns a 200.
Made-up AggregateRating. Showing 4.9 stars on a page with no visible reviews can lead to a manual penalty, and the risk is real.
What about variants?
If your product has multiple sizes or colors, there are 2 approaches:
Approach 1: one Product schema only (the parent)
Simpler, and suitable for 90% of cases. The parent schema describes the generic product, and the page handles variants through the selector. The displayed price is the default one, and availability is InStock if at least one variant is available.
Approach 2: ProductGroup with hasVariant
More precise but more complex. Recommended if your variants have very different prices or different availability states (out of stock in size 44 but not in 42). Google has supported ProductGroup since 2022.
FAQ
How long does it take for rich results to appear in Google?
Between 1 and 4 weeks after publishing the correct schema. Google needs to recrawl the page and trigger eligibility on the algorithm side. You can speed this up by submitting the URL through Search Console → URL Inspection → Request Indexing.
Does schema.org Product help the page rank?
Not directly. Schema is not a ranking signal. It enables rich results (stars, price, availability in the SERP), which increase CTR and can improve rankings indirectly through engagement signals.
Should I include full reviews in the JSON-LD, not just the aggregate?
Optional. Adding individual Review objects in the JSON-LD can enable more rich features, but it makes the code heavier. On catalogs with 5,000+ product pages, AggregateRating alone is more than enough.
Is schema penalized if my product page is generated by AI?
No. Google does not penalize content origin, it penalizes quality. Correct JSON-LD on a high-quality AI-generated page can get rich results just like any other page.
Should my JSON-LD be in <head> or <body>?
Both work, but <head> is the best practice. Place the JSON-LD right before the closing </head> tag to make sure crawlers read it early.
Do rich results also appear on Bing and DuckDuckGo?
Bing: yes, with a longer delay (sometimes 2-3 months). DuckDuckGo uses Bing as a backend, so yes indirectly. Both use the same schema.org standard, so no adaptation is needed.
On Ecomptimize, Product JSON-LD is generated automatically from your Shopify or WooCommerce catalog data. See the Shopify or WooCommerce page.
Did you enjoy this article?