Product Schema Markup for E-commerce: JSON-LD Examples That Pass Google’s Rich Results Test

Copy-ready JSON-LD examples for product pages, with offers, reviews, shipping, return policy, variants and breadcrumbs, and how to fix the most common structured data errors.

Structured data helps search engines understand your product pages: what the product is, what it costs, whether it is in stock and what customers think of it. With correct Product schema markup, your products can become eligible for rich results such as price, availability and review stars, and for merchant listing experiences in Google.

This guide gives you copy-ready JSON-LD examples and explains the errors I see most often.

Why JSON-LD?

Schema.org markup can be written as JSON-LD, Microdata or RDFa. Google recommends JSON-LD because it sits in a separate <script> tag and does not mix with your HTML, which makes it easier to maintain.

Basic Product example

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Trail Running Shoe X200",
  "image": [
    "https://www.example.com/images/x200-1.jpg",
    "https://www.example.com/images/x200-2.jpg"
  ],
  "description": "Lightweight trail running shoe with a grippy sole and waterproof upper.",
  "sku": "X200-BLK-42",
  "gtin13": "0123456789012",
  "brand": {
    "@type": "Brand",
    "name": "ExampleBrand"
  },
  "offers": {
    "@type": "Offer",
    "url": "https://www.example.com/trail-running-shoe-x200",
    "priceCurrency": "EUR",
    "price": "129.95",
    "availability": "https://schema.org/InStock",
    "itemCondition": "https://schema.org/NewCondition"
  }
}
</script>

Adding reviews and ratings

Only use review markup when the reviews are real and visible on the page.

"aggregateRating": {
  "@type": "AggregateRating",
  "ratingValue": "4.6",
  "reviewCount": "87"
},
"review": [{
  "@type": "Review",
  "author": { "@type": "Person", "name": "Anna" },
  "reviewRating": { "@type": "Rating", "ratingValue": "5" },
  "reviewBody": "Great grip on wet rocks."
}]

Shipping details and return policy

For merchant listings, Google can use shipping and return information. Add them inside the Offer:

"shippingDetails": {
  "@type": "OfferShippingDetails",
  "shippingRate": { "@type": "MonetaryAmount", "value": "0", "currency": "EUR" },
  "shippingDestination": { "@type": "DefinedRegion", "addressCountry": "NL" },
  "deliveryTime": {
    "@type": "ShippingDeliveryTime",
    "handlingTime": { "@type": "QuantitativeValue", "minValue": 0, "maxValue": 1, "unitCode": "DAY" },
    "transitTime": { "@type": "QuantitativeValue", "minValue": 1, "maxValue": 2, "unitCode": "DAY" }
  }
},
"hasMerchantReturnPolicy": {
  "@type": "MerchantReturnPolicy",
  "applicableCountry": "NL",
  "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
  "merchantReturnDays": 30,
  "returnMethod": "https://schema.org/ReturnByMail",
  "returnFees": "https://schema.org/FreeReturn"
}

Shipping and return policies can also be configured at account level in Google Merchant Center, or with organization-level markup. Keep all sources consistent.

Sale prices

To show a sale, use the current selling price in price. You can communicate the original price with a priceSpecification of type UnitPriceSpecification and a priceType of https://schema.org/StrikethroughPrice. Make sure the prices match what the visitor sees.

Product variants

For products with variants (size, colour), Google supports ProductGroup with hasVariant and variesBy:

{
  "@context": "https://schema.org",
  "@type": "ProductGroup",
  "name": "Trail Running Shoe X200",
  "productGroupID": "X200",
  "variesBy": ["https://schema.org/size", "https://schema.org/color"],
  "hasVariant": [
    {
      "@type": "Product",
      "sku": "X200-BLK-42",
      "size": "42",
      "color": "Black",
      "offers": { "@type": "Offer", "price": "129.95", "priceCurrency": "EUR", "availability": "https://schema.org/InStock" }
    },
    {
      "@type": "Product",
      "sku": "X200-BLK-43",
      "size": "43",
      "color": "Black",
      "offers": { "@type": "Offer", "price": "129.95", "priceCurrency": "EUR", "availability": "https://schema.org/OutOfStock" }
    }
  ]
}
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    { "@type": "ListItem", "position": 1, "name": "Shoes", "item": "https://www.example.com/shoes" },
    { "@type": "ListItem", "position": 2, "name": "Trail Running", "item": "https://www.example.com/shoes/trail-running" },
    { "@type": "ListItem", "position": 3, "name": "Trail Running Shoe X200" }
  ]
}

Organization (homepage)

{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Example Store",
  "url": "https://www.example.com",
  "logo": "https://www.example.com/logo.png",
  "sameAs": ["https://www.linkedin.com/company/example", "https://www.instagram.com/example"]
}

Common errors and how to fix them

Error or warning Cause Fix
Missing field “offers”, “review” or “aggregateRating” Product without any of these Add at least an Offer
Invalid price or currency Price with currency symbol or comma Use "129.95" and ISO currency "EUR"
Price mismatch Markup price differs from visible price Generate markup from the same data as the page
Duplicate Product blocks Theme and plugin/app both output markup Keep one complete source
Reviews not shown Reviews not visible on page, or self-serving markup Only mark up real, visible reviews
Availability wrong Cached markup after stock change Make sure cache invalidates on stock updates

How to test

  • Rich Results Test: checks eligibility for Google rich results
  • Schema Markup Validator (validator.schema.org): checks general Schema.org validity
  • Search Console enhancement reports: Product snippets and Merchant listings show errors across the whole site

Platform notes

  • WooCommerce: WooCommerce and SEO plugins output Product markup; avoid running two plugins that both add it.
  • Shopify: most themes include Product markup; review apps often add a second block (see my Shopify SEO checklist).
  • Magento 2: Luma uses Microdata; many stores switch to JSON-LD through an extension or custom templates, which is a good moment to add shipping and return data.

Frequently asked questions

Does structured data improve rankings?

Not directly. It makes pages eligible for richer search results, which can improve click-through rate, and helps search engines and AI systems understand your products.

Can I add review stars to every page?

No. Review markup should only be used for real reviews about the specific product, visible on that page.

Do I need GTINs?

Not always, but including GTIN, MPN and brand helps Google match your product, and is important for Merchant Center.

Need structured data that works?

I implement and fix structured data on WooCommerce, Shopify and Magento stores, including variants, shipping and returns. See my technical SEO service or request a review.