RovelaRovela
Back to the blog

By El Ghali Bennis · Published

Product Schema Markup Examples: Copy-Ready JSON-LD

Copy-ready product schema markup examples in JSON-LD: GTIN, offers, reviews, variants, shipping, returns and FAQs, plus how to validate them.

Product Schema Markup Examples: Copy-Ready JSON-LD

Product schema markup is a block of JSON-LD code that tells Google your page sells a specific product, including its name, price, availability and ratings. Below are copy-ready product schema markup examples, from a basic product to GTINs, multiple offers, variants, reviews, shipping, returns and FAQs, plus how to validate them.

Store owner typing structured data into a laptop beside a shelf of boxed ceramic mugs in a bright home studio

What Is Product Schema and Why Does It Matter?

Product schema is structured data, written in the schema.org vocabulary, that labels the facts on a product page so search engines can read them without guessing. Google uses it to show price, stock status and star ratings directly in search results.

Those enhanced listings are called rich results. For rich results product pages can display price, availability, review stars and shipping details under the title. Google's documentation on product structured data, at developers.google.com/search, lists exactly which properties it supports. The vocabulary itself lives at schema.org.

Structured data doesn't directly raise rankings. What it does is make your listing larger, clearer and more clickable. Google has published case studies on its Search Central site where retailers such as Rakuten and Nestlé reported higher engagement on pages with rich results, though results vary by site and you should measure your own click-through rate in Search Console. Structured data also gives AI search tools clean facts to quote. If you're working on that side, our guide to optimizing your website for ChatGPT covers the wider picture.

JSON-LD vs Microdata

Google recommends JSON-LD. It sits in one script block, separate from your HTML, so you can edit it without touching your layout. Microdata weaves attributes through the page markup and breaks easily when a theme changes. Every example below uses JSON-LD. Wrap each block in a <script type="application/ld+json"> tag in the page head or body.

Basic Product Schema Markup Example (JSON-LD)

A valid basic product needs a name and either an offer, a review or an aggregate rating. Here is the minimum I'd ship on any product page, with the fields Google reads most.

{
  "@context": "https://schema.org/",
  "@type": "Product",
  "name": "Stoneware Pour-Over Coffee Set",
  "image": [
    "https://example.com/images/pour-over-1x1.jpg",
    "https://example.com/images/pour-over-4x3.jpg"
  ],
  "description": "Hand-glazed stoneware dripper and carafe, 600 ml.",
  "sku": "POS-600-GRY",
  "mpn": "925872",
  "brand": {
    "@type": "Brand",
    "name": "Northfield Ceramics"
  },
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/pour-over-set",
    "priceCurrency": "USD",
    "price": "64.00",
    "priceValidUntil": "2026-12-31",
    "itemCondition": "https://schema.org/NewCondition",
    "availability": "https://schema.org/InStock"
  }
}

Offer schema availability and price

The offer schema availability price trio is what shoppers care about most. Three rules keep it clean:

  • Price is a plain number with a period as the decimal separator. No currency symbol, no commas.
  • priceCurrency uses the three-letter ISO 4217 code, such as USD, EUR or GBP.
  • availability uses a full schema.org URL. Common values are InStock, OutOfStock, PreOrder, BackOrder and SoldOut.

The markup must match what visitors see. If the page says $64 and the schema says $59, Google can flag the mismatch and drop your enhancements.

Adding GTIN identifiers

Global Trade Item Numbers help Google match your product to its catalog. Use the property that matches the length of your barcode: gtin8, gtin12 (UPC), gtin13 (EAN) or gtin14. Digits only, no spaces or dashes.

{
  "@context": "https://schema.org/",
  "@type": "Product",
  "name": "Stoneware Pour-Over Coffee Set",
  "sku": "POS-600-GRY",
  "gtin13": "0123456789012",
  "brand": { "@type": "Brand", "name": "Northfield Ceramics" },
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/pour-over-set",
    "priceCurrency": "USD",
    "price": "64.00",
    "availability": "https://schema.org/InStock"
  }
}

If your product has no barcode, such as a handmade item, leave GTIN out and rely on brand plus MPN or SKU. Never invent a number. A fake GTIN is worse than none.

Multiple offers with AggregateOffer

When one page shows a price range, for example several sellers or pack sizes, use AggregateOffer with a list of Offer items. Single-price pages should keep the simple Offer.

"offers": {
  "@type": "AggregateOffer",
  "priceCurrency": "USD",
  "lowPrice": "64.00",
  "highPrice": "112.00",
  "offerCount": "2",
  "offers": [
    {
      "@type": "Offer",
      "name": "Single set",
      "price": "64.00",
      "priceCurrency": "USD",
      "availability": "https://schema.org/InStock",
      "url": "https://example.com/pour-over-set"
    },
    {
      "@type": "Offer",
      "name": "Set of two",
      "price": "112.00",
      "priceCurrency": "USD",
      "availability": "https://schema.org/InStock",
      "url": "https://example.com/pour-over-set-2"
    }
  ]
}
Merchant comparing a product page on her phone with the code editor on her laptop at a kitchen table

Product Schema Examples for Reviews, Variants, Shipping and Returns

Once the basics work, you extend the same block with ratings, variants, shipping and return data. Each addition earns a different piece of the search listing.

AggregateRating schema on a product page

The aggregaterating schema product page pattern shows stars in results. Add it only when real customer reviews appear on the page itself. Here is a complete block you can paste and edit:

{
  "@context": "https://schema.org/",
  "@type": "Product",
  "name": "Stoneware Pour-Over Coffee Set",
  "sku": "POS-600-GRY",
  "brand": { "@type": "Brand", "name": "Northfield Ceramics" },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.7",
    "reviewCount": "132",
    "bestRating": "5",
    "worstRating": "1"
  },
  "review": [
    {
      "@type": "Review",
      "reviewRating": {
        "@type": "Rating",
        "ratingValue": "5",
        "bestRating": "5"
      },
      "author": { "@type": "Person", "name": "Dana R." },
      "datePublished": "2026-03-14",
      "reviewBody": "Pours evenly and looks great on the counter."
    }
  ],
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/pour-over-set",
    "priceCurrency": "USD",
    "price": "64.00",
    "availability": "https://schema.org/InStock"
  }
}

Never mark up reviews you wrote yourself or copied from another site. Google's guidelines treat that as a violation, and it can trigger a manual action.

Nesting reviews inside Product: pros and cons

You can nest review and aggregateRating inside the Product, as above, or publish reviews as separate blocks that reference the product. Nesting is the simpler choice, with tradeoffs:

  • Pro: one self-contained block is easy to validate and hard to break.
  • Pro: the rating is unambiguously tied to this product, not a category or the store.
  • Con: pages with hundreds of reviews make the block long, so include only a handful of recent reviews and keep the aggregate accurate.
  • Con: if a review app also outputs its own schema, you get duplicate Product markup. Disable one source.

Also, reviewCount should match the reviews users can see, and the average must be calculated from those same reviews.

Product variants with ProductGroup

If one product comes in several sizes or colors, use ProductGroup with each variant as its own Product. This keeps price and stock accurate per variant.

{
  "@context": "https://schema.org/",
  "@type": "ProductGroup",
  "name": "Linen Apron",
  "productGroupID": "APRON-LIN",
  "variesBy": ["https://schema.org/color", "https://schema.org/size"],
  "hasVariant": [
    {
      "@type": "Product",
      "sku": "APRON-LIN-SAGE-M",
      "name": "Linen Apron, Sage, M",
      "color": "Sage",
      "size": "M",
      "offers": {
        "@type": "Offer",
        "price": "48.00",
        "priceCurrency": "USD",
        "availability": "https://schema.org/InStock"
      }
    },
    {
      "@type": "Product",
      "sku": "APRON-LIN-CLAY-L",
      "name": "Linen Apron, Clay, L",
      "color": "Clay",
      "size": "L",
      "offers": {
        "@type": "Offer",
        "price": "48.00",
        "priceCurrency": "USD",
        "availability": "https://schema.org/OutOfStock"
      }
    }
  ]
}

Shipping and return details (full block)

Google also reads shipping and return policies inside the offer. Adding them can surface "Free shipping" or "30-day returns" labels in listings. This complete example includes both OfferShippingDetails and MerchantReturnPolicy:

{
  "@context": "https://schema.org/",
  "@type": "Product",
  "name": "Stoneware Pour-Over Coffee Set",
  "sku": "POS-600-GRY",
  "brand": { "@type": "Brand", "name": "Northfield Ceramics" },
  "offers": {
    "@type": "Offer",
    "url": "https://example.com/pour-over-set",
    "priceCurrency": "USD",
    "price": "64.00",
    "availability": "https://schema.org/InStock",
    "shippingDetails": {
      "@type": "OfferShippingDetails",
      "shippingRate": {
        "@type": "MonetaryAmount",
        "value": "0",
        "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"
    }
  }
}

Your markup has to reflect your real policy. If returns cost the customer, use https://schema.org/ReturnShippingFees and add a returnShippingFeesAmount. If you don't accept returns, use MerchantReturnNotPermitted as the category.

How to Add FAQPage Schema for Ecommerce

You add FAQPage schema as a second JSON-LD block on the same page, listing questions that appear visibly on your product page. Keep in mind that Google has sharply limited FAQ rich results, so treat it as a clarity signal for search engines and AI tools, not a guaranteed SERP feature.

That said, faqpage schema ecommerce pages still benefit. The questions force you to answer sizing, shipping and care concerns that block purchases. Here's the pattern:

{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "Is the pour-over set dishwasher safe?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes. Both pieces are dishwasher and microwave safe."
      }
    },
    {
      "@type": "Question",
      "name": "How long does shipping take?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Orders ship within one business day and arrive in 2 to 5 days."
      }
    }
  ]
}

Write answers from real customer emails, not guesses. If you need help drafting them, the prompts in AI prompts for product page design and ChatGPT prompts for product descriptions are a fast starting point.

Customer support owner reading a list of shopper questions on a notebook next to a laptop in a small office

How to Validate Product Structured Data

To validate product structured data, paste your URL or code into Google's Rich Results Test, then confirm the page in Search Console's Enhancements reports. The test shows errors, which block rich results, and warnings, which are optional improvements.

Use this checklist after every change:

  1. Run the live URL through Google's Rich Results Test at search.google.com/test/rich-results.
  2. Check the Schema Markup Validator at validator.schema.org for general syntax problems.
  3. Compare price, currency and stock in the code against what's visible on the page.
  4. Open Search Console's Product snippets and Merchant listings reports a few days later to catch errors at scale.
  5. Re-test after theme updates, app installs or price changes.

Common errors and fixes

ErrorCauseFix
Missing field "price"Offer has no price or it's emptyAdd a numeric price and priceCurrency
Invalid value for availabilityPlain text like "in stock"Use https://schema.org/InStock
Missing "aggregateRating" or "review"Product has neither offer nor ratingAdd an offer, or real review data
Price mismatchSchema differs from visible priceGenerate schema from the same data source as the page
Duplicate Product markupTheme and an app both output schemaDisable one source
Invalid GTINWrong length or property, or a made-up numberMatch gtin8/12/13/14 to the barcode digits

Product Schema Generators, Apps and Platform Options

You have three ways to produce this markup: write it by hand, use a product schema generator, or let your platform output it automatically. Automatic is the only option that scales past a few dozen products.

Free generators let you fill a form and copy the JSON-LD. They're fine for a handful of pages. For a catalog of 500 SKUs, you need markup generated from your product database, so price and stock never drift.

That's the weak point on many platforms. Here is how the common options compare on schema, based on how each is typically set up (check your own theme and plugins, since output varies):

PlatformProduct and OfferReviews and ratingsFAQ, shipping, returns
ShopifyTheme outputs basic Product and OfferUsually from a paid review appOften needs an app or theme edits; duplicates are common
WooCommerceCore output plus SEO pluginCore reviews feed rating markupPlugin settings or custom code you maintain
WixBuilt-in Product markupWix reviews appCustom structured data via the SEO panel, per page
RovelaGenerated from catalog dataBuilt from your catalog dataStandard Next.js code you can edit directly

When you're weighing schema markup for Shopify alternatives, ask one question: does the platform generate schema from live catalog data, or does it depend on an add-on? Also ask whether you can edit the raw JSON-LD, because shipping and return policies almost always need customizing.

On Rovela, product pages ship with structured data built from your catalog, and the store runs on standard Next.js code you can download, so any developer can inspect or extend the JSON-LD. For the broader question of search performance on AI-built sites, read do AI websites rank on Google, and for platform-level SEO prompts see ChatGPT prompts for ecommerce SEO.

Best practices for structured data for ecommerce

  • Generate JSON-LD from your product data, never by hand-typing prices.
  • Use one source of schema per page. Duplicates cause conflicts.
  • Mark up only what's visible to shoppers.
  • Include at least two or three high-resolution images in different aspect ratios.
  • Add GTIN or MPN when you have them. They help Google match your product to listings.
  • Keep availability current. An out-of-stock item marked InStock is a fast route to disapproved listings.
  • Update priceValidUntil before it passes, since expired dates can trigger warnings.

Your Next Step

Start with the basic example, add availability and price, then layer in GTINs, ratings, variants, shipping and returns once the first block validates cleanly. Test one product page, fix errors, then roll the same pattern across your catalog.

If maintaining schema through themes and apps sounds like a chore, Rovela builds stores with structured data generated from your catalog by default, plus 100+ built-in features and no per-app billing. You can see how it works on the Rovela homepage or check pricing to compare against your current platform and plugin costs.

Your dream store is one sentence away.