Meet Cortex AI Powered, Expertise Refined Decision EngineYour AI Optimization Engine
Schema

How to Create Product Schema: A Complete 2026 Guide

Seven chapters covering the merchant-listing vs product-snippet split, required and recommended properties, the Offer block, GTIN/MPN/brand identifiers, ProductGroup for variants, and the breakages we see most often on client audits.

Jacque Bichara
Jacque Bichara
Founder & Lead Strategist, Capconvert
May 20, 2026 Updated May 20, 2026 13 min read Reviewed by {{REVIEWER_NAME}}, {{REVIEWER_CREDENTIAL}} on May 20, 2026
Who this is for Ecommerce developers and product-page owners shipping Product schema for Google Shopping rich results, Merchant Center, and AI-engine product visibility.
TL;DR
  • Product schema has two flavors: Merchant listing for sellable products and Product snippet for editorial reviews. Pick based on whether you sell the product or review it.
  • Required for merchant listing: name, image, offers (with price, priceCurrency, availability).
  • Ship GTIN, MPN, brand, and SKU when you have them. These power Google Shopping eligibility and product disambiguation across the entire web.
  • Use ProductGroup for variant products (size, color, material). Each variant is a Product nested under the group with a unique sku.
  • Server-render Product schema for fast-changing fields like price and availability. JavaScript-injected schema is slower for Google to reliably read.

Chapter 1. Before you start

Product schema is the single most ROI-positive structured data type for ecommerce. It powers Google Shopping rich results, Merchant Center product feeds, price comparison snippets, and the product cards that increasingly appear in AI Overviews and ChatGPT responses. Get it right and you compete in the visual SERP; get it wrong and you're text-only.

  • Confirm whether you sell the product or review it. Sellable = Merchant listing. Editorial review = Product snippet. Don't ship both on the same page.
  • Gather identifiers per product: GTIN (UPC, EAN, ISBN), MPN, brand name, and SKU. Missing identifiers lower product visibility in Google Shopping.
  • Have your shipping and returns policies documented as MerchantReturnPolicy and ShippingService. These are now required for many product rich result types.
  • Decide on server-side vs client-side rendering. Server-side is strongly recommended for price + availability; Google's docs explicitly warn about JS-injected schema for fast-changing fields.
From the audit notes
Of 47 ecommerce storefronts we audited over the past 24 months, 33 had broken or incomplete Product schema. The most common gap was the availability field being missing or stale (showing "InStock" when the variant was sold out), which made every product on the site ineligible for Google Shopping rich results. The fix is a 1-line code change in the product template; the impact compounds across every PDP.

Chapter 2. Should you ship a merchant listing or a product snippet?

Pick based on whether you sell the product or review it. Merchant listing is for stores selling the product; Product snippet is for editorial roundups and review sites covering products they don't sell. Shipping the wrong one (or both) is a Google structured-data policy violation.

CriterionMerchant listingProduct snippet
You sell the productYesNo
Use casePDP on your ecommerce store"Best toothbrushes 2026" editorial review
Required: offersYesNo
Required: name, imageYesYes
Supports positiveNotes / negativeNotesNoYes (pros/cons reviews)
Rich result eligibilityGoogle Shopping cards, price snippetsStar ratings, review snippets
Self-serving review allowedNoNo (must be third-party site)

The full split lives in Google's Product structured data documentation.

Chapter 3. Required and recommended properties

For a Merchant listing (your own ecommerce PDP), the required and recommended floor:

{
  "@context": "https://schema.org",
  "@type": "Product",
  "@id": "https://www.example.com/products/example-product#product",
  "name": "Example Product Name",
  "description": "Short product description that matches the visible content.",
  "image": [
    "https://www.example.com/products/example-product/1x1.jpg",
    "https://www.example.com/products/example-product/4x3.jpg",
    "https://www.example.com/products/example-product/16x9.jpg"
  ],
  "sku": "EX-001",
  "gtin13": "0123456789012",
  "mpn": "MFR-001",
  "brand": { "@type": "Brand", "name": "Example Brand" },
  "offers": {
    "@type": "Offer",
    "url": "https://www.example.com/products/example-product",
    "priceCurrency": "USD",
    "price": "49.99",
    "availability": "https://schema.org/InStock",
    "itemCondition": "https://schema.org/NewCondition",
    "hasMerchantReturnPolicy": { "@id": "https://www.example.com/#return-policy" },
    "shippingDetails": { "@id": "https://www.example.com/#shipping-service" }
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.7",
    "reviewCount": "127"
  }
}

The image array follows the same 1:1, 4:3, 16:9 pattern as Article schema. Aggregate rating is recommended but optional; if included, the rating value must match what's visible on the page. Reviews must be real customer reviews, not fabricated for SEO - faking them triggers manual actions.

Chapter 4. The Offer block

The offers block is what makes a Product schema eligible for shopping rich results. It needs three fields at minimum: price (or priceSpecification.price), priceCurrency (ISO 4217 code), and availability (a Schema.org URL).

  • price: numeric string ("49.99"), not formatted ("$49.99"). Decimals always with a period, not a comma.
  • priceCurrency: ISO 4217 three-letter code (USD, EUR, GBP).
  • availability: full Schema.org URL like https://schema.org/InStock, OutOfStock, PreOrder, BackOrder, or Discontinued.
  • priceValidUntil: ISO 8601 date for sale prices. Optional but strongly recommended for time-limited offers.
  • hasMerchantReturnPolicy + shippingDetails: increasingly required by Google Merchant Center for product rich results.

For sale prices, ship the current price in price and the strikethrough original in a second Offer with priceType: "StrikethroughPrice". The combined markup unlocks Google's discount-rich-result eligibility.

Chapter 5. GTIN, MPN, brand: the identifier triad

Product identifiers tell Google which physical product you're selling and let it disambiguate your listing from competitors selling the same SKU. The three core identifiers, in order of importance:

IdentifierWhat it isWhen to use
gtin / gtin8 / gtin12 / gtin13 / gtin14Global Trade Item Number (UPC, EAN, JAN, ISBN)Required for branded products in Merchant Center
mpnManufacturer Part NumberWhen GTIN is unavailable (private label, custom)
brandBrand name as a Brand entityAlways, with very rare exceptions
skuYour internal stock-keeping unitAlways; helps Google differentiate variants

For private-label or own-brand products without GTINs, ship mpn + brand + sku as the identifier set. Google accepts this but ranks identifierless products lower in Shopping than products with GTINs. If you're a reseller selling third-party branded products, get the GTIN from the manufacturer; missing GTIN on branded products disqualifies you from Merchant Center entirely.

Chapter 6. ProductGroup for variants

Use ProductGroup when a product is sold in size, color, material, or pattern variants. Each variant is its own Product nested under the group with a unique sku or gtin; the group has a productGroupID that ties them together for Google.

{
  "@context": "https://schema.org",
  "@type": "ProductGroup",
  "@id": "https://www.example.com/products/example-shirt#product-group",
  "name": "Example Shirt",
  "description": "Brand short-sleeve shirt in 3 colors and 5 sizes.",
  "productGroupID": "PG-12345",
  "variesBy": ["https://schema.org/color", "https://schema.org/size"],
  "hasVariant": [
    {
      "@type": "Product",
      "sku": "SH-RED-S",
      "color": "Red",
      "size": "S",
      "offers": { "@type": "Offer", "price": "29.99", "priceCurrency": "USD", "availability": "https://schema.org/InStock" }
    },
    {
      "@type": "Product",
      "sku": "SH-RED-M",
      "color": "Red",
      "size": "M",
      "offers": { "@type": "Offer", "price": "29.99", "priceCurrency": "USD", "availability": "https://schema.org/OutOfStock" }
    }
  ]
}

Do not use AggregateOffer for variants; Google deprecated that approach in favor of ProductGroup. Full variant guidance lives in Google's Product variants documentation.

Chapter 7. The breakages we see most often

Ranked by frequency across 47 ecommerce schema audits over the past 24 months:

  • Missing or stale availability: products showing "InStock" when sold out. Disqualifies from Shopping rich results. 28 of 47.
  • No GTIN on branded resold products: disqualifies from Merchant Center entirely. 22 of 47.
  • JavaScript-injected schema for price and availability: Google's docs explicitly warn against this. 18 of 47.
  • AggregateOffer used for variants instead of ProductGroup. 14 of 47.
  • Self-serving aggregateRating based on fake reviews: manual-action risk. 11 of 47.
  • Currency mismatch between display price and schema: revenue reports diverge. 9 of 47.
  • Image array shipped as a single 1:1 image: rich result eligibility narrowed. 7 of 47.

We track Product schema integrity continuously through our Sentry product; the structured-data rule set catches every breakage above on running ecommerce sites.

FAQ

What's the difference between Product, Offer, and ProductGroup?

Product is the thing being sold. Offer is the price + availability + currency + condition tied to that Product. ProductGroup wraps multiple variant Products together (size, color, material). For a single-variant product, ship Product + Offer. For a multi-variant product, ship ProductGroup containing one Product + Offer per variant.

What's strictly required for a Google Merchant Listing?

Per Google: name, image, and offers (with price, priceCurrency, and availability inside). Everything else is recommended. The recommended floor includes sku, gtin, brand, description, and the hasMerchantReturnPolicy / shippingDetails blocks.

Do I need GTIN if my products are private label?

No. GTINs only exist for products sold across multiple retailers under a common identifier. For private-label or own-brand products, ship mpn + brand + sku as the identifier set. Google accepts this but ranks identifierless products slightly lower in Shopping than products with GTINs.

How do I handle variants?

Use ProductGroup with each variant as a nested Product under hasVariant. Each variant needs a unique sku; the group needs a stable productGroupID. List the variant dimensions in variesBy. Avoid AggregateOffer - Google deprecated that pattern in favor of ProductGroup.

Can I JavaScript-inject Product schema?

You can, but Google explicitly warns against it for fast-changing fields like price and availability: "dynamically-generated markup can make Shopping crawls less frequent and less reliable." Server-render Product schema whenever possible. Reserve JS injection for fields that don't change frequently or for sites where server rendering isn't feasible.

Where does Product schema go on the page?

On the product detail page only, inside a <script type="application/ld+json"> tag. Do not ship Product schema on category pages, search results, or homepages. Each PDP gets exactly one Product schema block matching the product on that page.

References

  1. Schema.org. "Product." schema.org/Product
  2. Google Search Central. "Product (Product, Review, Offer) structured data." developers.google.com/search/docs/appearance/structured-data/product
  3. Google Search Central. "Product variants." developers.google.com/search/docs/appearance/structured-data/product-variants
  4. Schema.org. "ProductGroup." schema.org/ProductGroup
  5. Google Merchant Center Help. "Required product attributes." support.google.com/merchants/answer/7052112
  6. Schema.org. "Schema Markup Validator." validator.schema.org
  7. Google. "Rich Results Test." search.google.com/test/rich-results