Product structured data: how to implement it so it matches the page
Markup tells a search engine what your page means. Markup that disagrees with what a person can see is not a technicality — it is the thing that earns a manual action.
Structured data is how a product page stops being text and starts being a record: a price, a currency, an availability, a rating. Get it right and you become eligible for rich results that take up more of the page and get clicked more.
Get it wrong in the specific way most shops do — markup saying something the page does not — and you are not merely ineligible. You are misrepresenting the page, which is a policy problem rather than a technical one.
The properties that actually do work
Use JSON-LD in a script tag. Microdata still works but is harder to keep correct as templates change.
- name, image, description, sku, brand — the identity of the thing.
- gtin where one exists. It links your item to the product search engines already know, and its absence limits what you are eligible for.
- offers with
price,priceCurrency,availabilityandpriceValidUntil. This is the block that is checked hardest. - aggregateRating and review — only if real reviews are visibly on the page.
- shippingDetails and hasMerchantReturnPolicy, which increasingly influence how a listing is presented and are worth the effort.
Everything must match the visible page
- Price. Same number, same currency, same tax treatment as displayed. A page showing an inc-VAT price and markup carrying the ex-VAT one is a mismatch.
- Availability.
InStockonly if it is. - Ratings. Markup an aggregate rating only where the reviews are rendered on that page. Marking up ratings that live elsewhere, or that are for the brand rather than the product, is the most common cause of a structured data manual action.
- Sale prices need their validity dates, or the discount becomes the price you are asserting indefinitely.
Variants, done properly
A product with sizes or colours should use ProductGroup with hasVariant, and each variant carries its own sku, price and availability. The alternative — one Product with an AggregateOffer spanning a price range — is acceptable but weaker, and it matches queries you may not be able to fulfil at the lowest price.
Whichever you choose, the variant selected on the page and the markup must agree. A page that defaults to the medium and marks up the small is the same mismatch class as a wrong price.
The other three types worth having
- BreadcrumbList on every product and category page. Cheap, mechanical, and it changes how the URL is displayed in results.
- Organization on the home page, with your logo, name and contact points. This is what feeds brand panels.
- FAQPage, but only where genuine questions and answers are visible on the page. Its eligibility for rich results has narrowed considerably, and fabricated FAQ blocks added purely for markup are exactly what that change was aimed at.
How to test it, and when
Validate with Google's Rich Results Test on the rendered page, not on your template. If your markup is injected by JavaScript, test the rendered output, because what the crawler sees may differ from what your editor shows.
- Test one page per template type, not one page. Simple product, variable product, out-of-stock product, sale product.
- Re-test after any theme or plugin update. This is the moment it silently breaks.
- Watch Search Console's enhancement reports weekly. A sudden count of errors is nearly always one upstream change, not a thousand individual problems.
Sources and further reading (4)
- Google — Product structured data
- Google — Structured data general guidelines
- Google — Review snippet
- Schema.org — ProductGroup
Checked on 23 September 2026. Provider prices, mailbox rules and legal guidance change — verify anything you plan to act on.
Markup that cannot drift from your shop
Auralata reads price, currency, stock and whether that shop shows prices with tax included straight from WooCommerce, so what you publish about a product is what the product actually is.