Product schema is structured data that describes a single product on a page: its name, images, price, currency, stock status and, where you have them, reviews and identifiers. Google can use it to show richer product information, such as price and availability, in search and in places like Google Images. It is the markup most online shops need, and it is also where most mistakes happen, because prices and stock change all the time.
This guide is for shop owners and developers who want to add product schema markup to product pages and keep it correct. You will learn the difference between the two main Google product experiences, which properties are required, how to write a clean JSON-LD block, and how to test it. You will also see what the markup cannot do. It does not ensure that a rich result will appear, and it will not make a weak product page rank.
Before you begin
You need access to the product page template (or your shop platform's structured data settings) and a sample of live product URLs to test. If your platform already outputs Product markup, find out what it produces before you add anything: duplicate or conflicting blocks are a common problem. Many platforms and plugins handle the basics, and in that case your job is to check them and fill the gaps.
Have these ready for one real product:
- The product name exactly as shown on the page.
- At least one product image URL that Google can crawl.
- The current price as a number, and the three-letter currency code.
- The stock status shown on the page.
- A brand, SKU, and a GTIN or MPN if the product has them.
Set aside an hour for the first product template. Back up the template before editing. If you also use Google Merchant Center, keep its data consistent with the page, because Google says providing both page markup and feed data maximizes eligibility and helps it verify your data.
Product snippets and merchant listings
Google describes two classes of product markup, plus variant markup that both support.
Product snippets are for product pages where people cannot buy the product directly, such as an editorial review. They offer more options for review information.
Merchant listings are for pages where customers can buy the product from you. They allow more detail, such as shipping and return policy.
Both use the Product type. Google notes that adding the properties required for merchant listings also makes a page potentially eligible for product snippets, and adding more properties makes it eligible for more enhancements. Enhancements, such as ratings, shipping, availability and returns, are shown at each experience's discretion and may change.
Whichever you aim for, follow the page rule: Product markup is for pages that focus on a single product, or on variants of the same product. A category page that lists many products is not supported.
Step-by-step instructions
Step 1: Decide whether the page can sell the product
Look at the page. If a visitor can add the product to a basket and buy it from you, aim for merchant listing markup. If the page is a review or a comparison that sends people elsewhere to buy, product snippet markup is the fit. Pages that only link out to other sellers are not eligible for merchant listings.
What success looks like: each template is labeled as a buyable product page or a review page, and category pages are excluded.
Step 2: Add the required properties
For merchant listings, Google requires name, image and an offers object. Inside the offer, the current price (price, or priceSpecification.price) and the three-letter ISO 4217 currency code (priceCurrency) are required. The offer must be an Offer, not an AggregateOffer, because the merchant has to be the seller.
For product snippets, name is required, plus at least one of review, aggregateRating or offers. Google notes the Rich Results Test may warn if you give offers without a review or rating.
Google recommends several high-resolution images, at least 50,000 pixels each, in 16:9, 4:3 and 1:1 aspect ratios. Image URLs must be crawlable and indexable.
What success looks like: the block contains a name, an image, an offer with price and currency, and nothing that is not on the page.
Step 3: Write the JSON-LD
Here is a minimal merchant listing example. All values are placeholders on example.com:
{
"@context": "https://schema.org/",
"@type": "Product",
"name": "Terracotta Planter, 30 cm",
"image": [
"https://www.example.com/photos/planter-1x1.jpg",
"https://www.example.com/photos/planter-4x3.jpg"
],
"description": "Frost-resistant terracotta planter with drainage hole.",
"sku": "PLANT-30-TC",
"brand": { "@type": "Brand", "name": "Example Pots" },
"offers": {
"@type": "Offer",
"url": "https://www.example.com/planters/terracotta-30",
"price": 24.99,
"priceCurrency": "GBP",
"availability": "https://schema.org/InStock",
"priceValidUntil": "2026-12-31"
}
}
Use a period as the decimal separator (24.99, not 24,99) and always include the currency code. If you sell in several currencies, Google asks for a separate URL for each currency.
What success looks like: the block parses, and each value matches the visible page.
Step 4: Get price rules right
Merchant listings need a price greater than zero. The active price goes at the offer level or inside a priceSpecification; if both are present, Google uses offers.price. For a crossed-out original price, use priceType with https://schema.org/StrikethroughPrice, and do not put priceType on the active price. For sale periods, use validFrom and validThrough or priceValidUntil in ISO 8601 format. A priceValidUntil date in the past can stop the listing from displaying, so generate the date from your system or leave it out rather than hard-coding a date that expires.
Do not combine a member price (validForMemberTier) with priceType. Google ignores price specifications that carry both.
What success looks like: the price in the markup is the price a shopper pays today.
Step 5: Set availability with one value
Pick one availability value. Google accepts InStock, OutOfStock, PreOrder, BackOrder, SoldOut, LimitedAvailability, OnlineOnly, InStoreOnly, Discontinued and PreSale. Short names without the schema.org prefix are also accepted. Tie the value to your stock system so it changes when the page changes.
What success looks like: marking a test item out of stock changes the page text and the markup together.
Step 6: Add recommended details that you really have
Recommended product properties include brand.name, sku, mpn, the most specific GTIN you hold, description, color, size, material and review data. For offers, shippingDetails, hasMerchantReturnPolicy and itemCondition are recommended. Shipping and return policies can be defined once on your organization markup instead, as described in Organization Schema Markup, or per product when policies differ.
Add reviews only if real customers wrote them and the reviews are visible on the page. Google's review guidelines say not to combine ratings from other websites into your aggregate, and reviews must be about one specific item. If you include individual reviews, include an aggregate rating too.
What success looks like: every optional property in the block is accurate, and the Rich Results Test lists fewer warnings.
Step 7: Handle variants
Each variant can be marked up if it has its own distinct URL. Google's variant markup uses properties such as inProductGroupWithID and isVariantOf to tell it which products belong to the same parent. Do not use AggregateOffer to describe variants. Google says variants need a distinct URL each to be included, so a page that swaps variants without changing its URL gives Google nothing separate to list.
What success looks like: each variant URL shows its own price, size or colour in the page and in the markup.
Step 8: Put it in the initial HTML
Google recommends that Product markup be in the initial HTML. Markup generated by JavaScript can make Shopping crawls less frequent and less reliable, especially for fast-changing data like price and availability, and it can add crawl load on your server. If your platform injects markup after the page loads, check what Google sees using the rendered HTML in the URL Inspection tool, and move the markup server-side if you can.
What success looks like: viewing the raw page source shows the Product block.
Step 9: Test and monitor
Test one URL in the Rich Results Test, fix errors, then roll the template out to a handful of products and test again. After launch, watch the Search Console reports for product items. Our guides on Test and Debug JSON-LD Structured Data and Fix the Most Common Rich Results Test Errors and Warnings explain how to read the results. Remember Google's guidance that valid markup alone does not ensure a rich result is displayed.
What success looks like: the test shows valid Product items, and Search Console shows no new errors after launch.
Final verification checklist
- Each product page covers one product, or variants of one product.
name,imageandoffersare present for merchant listings.- The offer has a price above zero and a three-letter currency code.
- The availability value is one of the accepted values and matches the page.
priceValidUntilis in the future, or absent.- Variants each have their own URL.
- Reviews and ratings are real, visible on the page and about this product.
- The Product block is present in the raw HTML.
- The Rich Results Test shows no errors for sample URLs.
- Merchant Center data, if used, matches the page.
Common mistakes to avoid
- Marking up category pages. Product markup is for single-product pages. Remove it from listing pages.
- Stale prices. Generate price and availability from the same data as the page, so they cannot drift.
- Expired
priceValidUntil. A past date can prevent the listing from displaying. Compute it or omit it. - Missing currency. A bare number is ambiguous. Always add
priceCurrency. - Using
AggregateOfferfor a merchant listing. Use a singleOffer. - Two currencies on one URL. Give each currency its own URL.
- Reviews copied from elsewhere. Use only genuine reviews from your own customers that visitors can see.
- Markup only added by JavaScript. Put it in the initial HTML where possible.
Frequently asked questions
Do I need Merchant Center as well?
No. Google says you can use page markup, a Merchant Center feed, or both. Using both helps it verify the data.
Is a GTIN required?
Google lists GTIN, MPN and SKU as recommended, not required, for merchant listings. The Rich Results Test can flag a missing global identifier, so add the most specific one you have.
Why does my price not show in search?
Google decides what to show for each experience. Check that the markup is valid, matches the visible price, has a future or absent priceValidUntil, and that the page is crawlable. Even then, display is not assured.
Can a free product use schema?
For product snippets a price of 0 is valid. Merchant listings require a price above zero.
Does the markup help my product rank higher?
Google describes it as helping it understand the page and enabling richer appearances. It does not describe it as a ranking boost.
Related guides
- Organization Schema Markup: Add Your Name, Logo and Profiles
- JSON-LD Validation: Test and Debug Structured Data Step by Step
- Rich Results Test Errors: Fix the Most Common Problems and Warnings
- Fix Duplicate URLs and Incorrect Canonical Tags
Official references
- https://developers.google.com/search/docs/appearance/structured-data/product
- https://developers.google.com/search/docs/appearance/structured-data/merchant-listing
- https://developers.google.com/search/docs/appearance/structured-data/product-snippet
- https://developers.google.com/search/docs/appearance/structured-data/review-snippet
- https://developers.google.com/search/docs/appearance/structured-data/sd-policies
Next step: See how Crawvix checks a website and capture a baseline once scanning opens. This guide provides technical information, not a guarantee of rankings, traffic or index inclusion.