Shopify themes auto-emit a Product JSON-LD block on every product page1 — name, image, description, an offers object with price and availability, plus sku and (on most themes) brand mapped from product.vendor. Dawn and Horizon build it with Shopify's structured_data filter, which prints a Product for a product without variants and a ProductGroup when it has variants14. The 2026 install rule: keep one Product entity per page. To add fields, replace the theme's line in main-product.liquid4 with your own complete block rather than adding a second one. What the theme's output leaves out: itemCondition, hasMerchantReturnPolicy, shippingDetails, and aggregateRating + review (only when real customer reviews exist). gtin is printed only when the variant's Barcode field is filled in15.
Google's Product documentation6 defines two surfaces — Product snippets (pages where people can't buy the product directly, like editorial reviews) and Merchant listings (pages where customers can buy). Shopify PDPs are Merchant listings. Structured data alone can make them eligible; a Google Merchant Center feed is optional, and Google says using both "maximizes your eligibility to experiences." Filling the fields on Shopify's Catalog optimisation list2 (barcode, vendor, variants) feeds both.
§01Definition
What Product schema is
Product is the Schema.org type for a physical or digital good offered for sale. Per Schema.org v30.0, Product properties include name (Text), image (ImageObject or URL), description, brand (Brand or Organization), sku, gtin / gtin8 / gtin12 / gtin13 / gtin14 (Text identifiers), mpn (Manufacturer Part Number), offers (Offer with price + availability), aggregateRating, review, plus variant-related properties isVariantOf and hasVariant for ProductGroup composition. The mental model: Product describes the item itself; Offer describes the transaction. A Shopify PDP carries both.
What's missing from Shopify's auto-emission — itemCondition, AggregateRating from real reviews, hasMerchantReturnPolicy, shippingDetails, and a gtin wherever the Barcode field is empty — is what Google's merchant listing documentation lists as recommended10. Schema.org v30.0 dates from 2026-03-195; the Product type has been stable across the last several vocabulary versions, so the field set you author today will not break next quarter.
§02When
When to use Product schema on Shopify
Use Product on every product page on a Shopify store. The schema applies to physical goods (apparel, jewellery, furniture, food), digital goods (downloads, courses), and services sold as packaged products (a one-off coaching package, a fixed-price installation). Do not use Product on collection pages — those are CollectionPage or ItemList. Do not use Product on the homepage. Do not use Product on the cart, search, or checkout routes (which Shopify blocks from indexing by default anyway via robots.txt).
An edge case worth naming: services sold as fixed-price products on Shopify. If the customer takes possession of a digital good (a course they download), use Product. If the customer receives ongoing service delivery, Schema.org's Service type is technically more accurate — but Shopify's product model treats both identically, and Product is the more familiar type to AI shopping engines. For Shopify-sold services, Product is the practical choice unless the page is explicitly framed as ongoing service provision.
§03The auto-emitted layer
What Shopify themes already emit
Dawn (since v15.0.0) and Horizon print the product's JSON-LD with one line, {{ product | structured_data }}. Shopify's filter outputs a Product for a product without variants and a ProductGroup for a product with variants. On the Dawn demo store (read 2026-09-16) a multi-variant product comes out as a ProductGroup with @id /products/[handle]#product, name, description, brand (from product.vendor), productGroupID and url, plus one Product per variant in hasVariant, each with name, sku, image, gtin when the variant's Barcode field is filled, and an Offer with price, priceCurrency, availability and url. What the filter does NOT emit: itemCondition, variesBy, hasMerchantReturnPolicy, shippingDetails, aggregateRating, review. Older and third-party themes differ, so view source before you write anything.
The implication: adding to Product schema on Shopify means editing the one block the page already has, not adding a second one next to it. Two separate descriptions of the same product give Google two Product entities for one page. Either keep the theme's output and put store-wide policies on Organization (see below), or replace the theme's line with a block of your own that carries every field.
§04Rich results
Rich-results status in 2026
Product structured data drives two distinct Google surfaces in 2026. Product snippets are for pages where people can't buy the product directly, such as review and comparison pages; they need name plus one of offers, review or aggregateRating. Merchant listings are for pages where customers can buy, which is every Shopify PDP; they need name, image and an Offer with a price above zero and a priceCurrency. Structured data on the page is enough to be eligible for merchant listing experiences. A Merchant Center feed is optional, and Google recommends doing both.
The honest framing: the auto-emitted Shopify Product schema already carries every field Google requires for a merchant listing, as long as the product has an image and a price above zero10. What it lacks are recommended fields: shipping and return details (which Google prefers you declare once for the store on Organization), itemCondition, and ratings from real reviews. Google never guarantees a rich result, so treat the recommended fields as eligibility for richer listings, not a promise of them.
Product schema on Shopify in 2026
2
Google surfaces Product schema feeds: Product snippets (pages where you can't buy) and Merchant listings (pages where you can).
For a merchant listing on a Shopify PDP, Google requires name, image and offers, with the Offer carrying price (greater than zero) and priceCurrency. A product snippet needs only name plus one of offers, review or aggregateRating. Recommended for merchant listings: brand, gtin (the most specific of gtin8/gtin12/gtin13/gtin14 that applies), mpn, sku, description, aggregateRating, review, and on the Offer availability, itemCondition, hasMerchantReturnPolicy and shippingDetails. The fields most worth adding because Shopify's structured_data output leaves them out: itemCondition, aggregateRating (when real customer reviews exist), and return and shipping policies.
name — required. Auto-emitted by Shopify themes from product.title.
image — required for merchant listings. Auto-emitted from the product or variant image. Image URLs must be crawlable and indexable.
description — recommended. Auto-emitted from product.description (stripped).
brand — recommended. Most Shopify themes emit a Brand object from product.vendor. If yours does not, add it.
sku — recommended. Auto-emitted from the variant's SKU. Google rejects whitespace in it.
gtin / gtin8 / gtin12 / gtin13 / gtin14 — recommended. Dawn and Horizon print the variant's barcode as gtin when the Barcode field is filled; Google prefers the most specific length property. The GTIN leaf maps it by length.
mpn — Manufacturer Part Number. Recommended when gtin is unavailable. Shopify does not have a native MPN field; use a metafield (e.g. custom.mpn) and reference it via Liquid.
offers — required for merchant listings. Auto-emitted with price, priceCurrency, availability, url. See the Offer leaf for the full sub-object spec.
aggregateRating — recommended. NOT auto-emitted. Add only when real customer reviews are visible on the page. See the AggregateRating leaf.
review — recommended. Individual reviews as Review objects.
hasMerchantReturnPolicy — recommended on the Offer. NOT auto-emitted. Google prefers one store-wide policy on Organization, with Offer-level policies for exceptions. See the hasMerchantReturnPolicy leaf.
shippingDetails — recommended on the Offer. NOT auto-emitted. Same rule: store-wide shipping goes on Organization. See the shippingDetails leaf.
productID — optional Schema.org property. Google's product documentation doesn't list it, so it adds nothing for rich results.
§06Example
Full Liquid-driven JSON-LD example for a Shopify PDP
The block below is the full Product schema for a Shopify-sold ceramic vase with no variants. It carries the fields the theme already prints plus the ones it leaves out (itemCondition, a return policy, shipping details), built from Liquid variables so it re-renders per product. In the theme's main-product.liquid, find the line that prints {{ product | structured_data }} inside a script tag and replace it with this block. Products with variants fall through to the theme's own ProductGroup.
JSON-LDOne Product block for a single-variant Shopify PDP. It replaces the theme's structured_data line; products with variants keep the theme's ProductGroup
Product schema goes inside main-product.liquid (modern themes) or product-template.liquid (older themes). Open the theme's code editor (Online Store > Themes > Actions > Edit code) or pull the theme down via Shopify CLI. Find the section file for the product template and the script tag that prints the structured_data filter. Replace that tag with the block above. Save. Push if using CLI. View source on the live product page after deployment: a product without variants should show your block and no other Product; a product with variants should still show the theme's ProductGroup.
An alternative pattern for stores already using JSON-LD via a schema app (JSON-LD for SEO, Smart SEO, Avada): pick one source for Product. Either disable the app's Product schema, or remove the theme's structured_data line and let the app own Product entirely. The app-vs-native trade-off is covered on the schema-app-vs-theme leaf; for stores doing the install themselves, the theme-native approach above keeps the markup in main-product.liquid, the section Shopify's own SEO FAQ identifies as generating the product page's H14.
§08Validation
Validation steps
Run the live product page URL through Google's Rich Results Test. The expected output: one Product (or ProductGroup) detected under Merchant listings, zero errors, and warnings only on recommended fields you haven't added, typically hasMerchantReturnPolicy and shippingDetails when you haven't declared them. If you use Merchant Center as well, check there that the feed and the page agree; that check happens in the Merchant Center console, not in the Rich Results Test.
A common validation gotcha on Shopify: the test reports a missing identifier on a product whose Barcode field is empty. Don't fabricate a GTIN to silence the warning. If your products legitimately don't have one (handmade, vintage), leave the field unset. If the Barcode field is filled and no gtin appears in view-source, your theme predates the structured_data filter or builds its own block; add the gtin line from the example.
§09Gotchas
Common Shopify gotchas
Five gotchas catch most Shopify Product schema work. First: adding a second Product block next to the theme's, which gives Google two descriptions of one product. Second: forgetting to divide the price by 100.0 (Shopify stores prices in the currency's subunit). Third: printing product.title or product.vendor inside quote marks instead of through the | json filter (| escape is for HTML and doesn't make a value JSON-safe), causing JSON syntax errors when titles contain double quotes or line breaks. Fourth: marking up ratings shoppers can't see on the page, or ratings copied from another site; Google's review snippet rules require ratings that are visible and sourced directly from users. Fifth: leaving Product schema in theme.liquid (a site-wide template), where product.* variables are unbound on non-product pages and the schema fails to render.
A sixth gotcha for variant products: a single Product block describes one variant. If you sell a product in five sizes or three colours, Google's variant documentation models it as a ProductGroup with one Product per variant in hasVariant, each with its own ID such as the SKU or GTIN12. Dawn and Horizon already output that shape through the structured_data filter14, which is why the example above only replaces the block for products without variants. Older themes that print a single Product for every product need a ProductGroup block written by hand.
§10Related
Related schema types
Product references Brand (its own Schema.org type, not an Organization subtype, though brand also accepts an Organization) and contains Offer (the pricing sub-object). When real customer reviews are shown on the page, Review and AggregateRating layer in. BreadcrumbList belongs on every product page. For variant products, ProductGroup is the parent type. The Organization that owns the catalog should also have its own site-wide schema block in theme.liquid.
Offer schema — the transaction sub-object inside Product.
Brand schema — the manufacturer/vendor entity inside Product.