Product Schema Example for Shopify Apparel
Copy-ready JSON-LD Product and ProductGroup schema examples for Shopify apparel — covers size and color variants, offers, breadcrumbs, and the AggregateRating rules that decide whether AI search engines actually cite your product page.
Apparel product pages on Shopify get cited by AI shopping engines based
on how precisely the JSON-LD describes the variant landscape. A
shopper asking “linen shirt that runs true to size in medium” on
ChatGPT, Perplexity, or Gemini needs the AI to recognise that the
specific variant exists, is in stock, has a price, and is described
distinctly from the L and XL siblings. Generic Product schema with no
variant detail forces the AI to guess; ProductGroup with hasVariant
gives it the data to cite confidently.
This example ships two copy-ready JSON-LD blocks: a ProductGroup for
the variant matrix, and a BreadcrumbList for category context. Both
are calibrated to pass Google Rich Results Test cleanly and to mirror
the visible page content (the rule AI engines actually enforce in
practice).
When to use Product vs ProductGroup
| Use case | Schema | Why |
|---|---|---|
| Single-SKU item (one size, one color) | Product | No variant matrix to express — adding ProductGroup is overkill. |
| Apparel with size variants only | ProductGroup + variesBy: size | AI shopping queries are size-conditioned; flat Product loses that. |
| Apparel with color variants only | ProductGroup + variesBy: color | AI queries are color-conditioned. |
| Apparel with size × color matrix | ProductGroup + both variesBy | Cartesian product of variants; each hasVariant is the unique SKU. |
| Bundle / kit (multiple parents) | Product per item + custom isRelatedTo | ProductGroup describes one product’s variants, not multi-product bundles. |
Shopify’s default Liquid templates emit Product regardless of variant
count. Upgrading to ProductGroup for any apparel store with multiple
sizes is a one-time theme edit (or a Shopify App that handles it
automatically); the AI-shopping citation lift is worth the effort.
ProductGroup JSON-LD (apparel with variants)
Drop this into a product page template, replacing the placeholder
values. The example shows a 2-variant subset; in production you’ll have
one hasVariant entry per real SKU.
{
"@context": "https://schema.org",
"@type": "ProductGroup",
"name": "Linen Relaxed Shirt",
"description": "A breathable linen shirt in three colors, sizes XS–XL. 100% European linen, pre-washed for softness.",
"brand": {
"@type": "Brand",
"name": "Example Apparel"
},
"productGroupID": "linen-shirt-001",
"variesBy": ["https://schema.org/size", "https://schema.org/color"],
"hasVariant": [
{
"@type": "Product",
"sku": "LINEN-SHIRT-WHITE-M",
"name": "Linen Relaxed Shirt — White / M",
"color": "White",
"size": "M",
"material": "Linen",
"image": "https://example.com/products/linen-shirt-white.jpg",
"offers": {
"@type": "Offer",
"url": "https://example.com/products/linen-shirt?variant=white-m",
"priceCurrency": "USD",
"price": "79.00",
"availability": "https://schema.org/InStock",
"itemCondition": "https://schema.org/NewCondition"
}
},
{
"@type": "Product",
"sku": "LINEN-SHIRT-BLACK-S",
"name": "Linen Relaxed Shirt — Black / S",
"color": "Black",
"size": "S",
"material": "Linen",
"image": "https://example.com/products/linen-shirt-black.jpg",
"offers": {
"@type": "Offer",
"url": "https://example.com/products/linen-shirt?variant=black-s",
"priceCurrency": "USD",
"price": "79.00",
"availability": "https://schema.org/InStock",
"itemCondition": "https://schema.org/NewCondition"
}
}
]
} BreadcrumbList JSON-LD
Pair the ProductGroup with a BreadcrumbList so AI engines understand
the category hierarchy your product lives in. The breadcrumb URLs must
match the page’s visible breadcrumb exactly.
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://example.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "Shirts",
"item": "https://example.com/collections/shirts"
},
{
"@type": "ListItem",
"position": 3,
"name": "Linen Relaxed Shirt",
"item": "https://example.com/products/linen-shirt"
}
]
} Common errors (in order of how often they trip stores up)
-
Marking up variants that aren’t visible or selectable on the page. Schema must mirror visible reality. If your product page only shows S / M / L but the JSON-LD declares XS through XXL, AI engines will eventually try to cite a variant that 404s and downweight the store.
-
Using
AggregateRatingwhen no review widget exists. Either show the reviews visibly (use a Shopify Reviews app) or drop the schema field. Don’t fabricate. -
Inconsistent currency, price, or availability between schema and the visible product page. Buyer sees
$79but schema declares89.00— AI engines pick the schema number, cite it, and the buyer feels misled. Worse, Google flags the schema as untrustworthy. -
Reusing the same
skuacross variants. Shopify auto-generates unique SKUs but merchants often override them. Duplicate SKUs inhasVariantcause AI engines to merge variants incorrectly. -
Mixing
ProductGroupandProductsuch that variant-specific names get lost. If you emit bothProductandProductGroupfor the same item, make sure theProductinstance is the parent (no variant detail) andProductGroup.hasVariantcontains the variants. Don’t emitProductfor each variant outside the group. -
Adding medical or unsupported claims to apparel descriptions. “Posture-correcting” / “improves circulation” / “anti-bacterial fabric prevents skin disease” — these are regulated claims in most markets and trigger AI engine downweighting even when legally fine. Stick to fit and material descriptions.
-
Pointing schema URLs at non-canonical variant URLs. If the page uses one canonical product URL (e.g.
/products/linen-shirt) and variants are query-param selected (?variant=white-m), thehasVariant[].offers.urlshould still point at the variant-specific URL — that’s where buyers (and AI agents) land.
How to verify
- Paste the deployed product URL into
Google Rich Results Test
. TheProductandBreadcrumbListitems should both validate. - Run the validation checklist above against each field.
- Open the page in an incognito window and check that the visible product H1, price, availability, and breadcrumb all match what the schema declares.
- Re-run the Schema Generator if you change product structure (new color, dropped size) and re-deploy.
The JSON-LD is one signal in the AI-shopping stack. Pair it with the Fashion llms.txt template for the content-map side, and verify that GPTBot can reach the product page using the Robots Analyzer.
Validation checklist
Product name in schema matches the visible H1
The `name` field of ProductGroup matches the H1 on the product page exactly (case + punctuation). AI engines downweight mismatches as a low-trust signal.
Each variant has a unique SKU
No two `hasVariant[].sku` values collide. Shopify auto-generates variant SKUs but merchants often override them — duplicate SKUs in schema cause AI engines to merge variants incorrectly.
Variant names identify size / color / material
Each `hasVariant[].name` reads like a real product label (e.g. 'Linen Relaxed Shirt - White / M'), not a placeholder. AI shopping answers quote this field directly.
productGroupID is stable across deploys
The `productGroupID` should be a stable internal identifier (Shopify product GID or a custom slug), not a random build-time UUID. AI engines use this to deduplicate the same product across page reloads.
Every Offer has currency + price + availability + URL
Each variant's `offers` block has `priceCurrency`, `price`, `availability`, and `url`. Missing currency is the #1 reason Google Rich Results Test downgrades a Product result.
AggregateRating only present if real reviews are visible
If you emit `aggregateRating`, the same rating + review count must be visible on the product page. AI engines compare schema to visible page content; fabricated ratings trigger downweighting.
BreadcrumbList matches the visible breadcrumb
The schema's `itemListElement` URL chain matches the visible breadcrumb on the page exactly (same path, same labels). Mismatches confuse AI engines that use breadcrumb context for category understanding.
Rich Results Test returns no critical errors
After deploying, paste the product URL into https://search.google.com/test/rich-results — the Product and BreadcrumbList items should both validate with no critical errors.
Open in Schema Generator
Prefilled with apparel-store placeholders for product name, description, brand, price, availability, and ratings. Replace placeholders with your real product data and download a Shopify-ready JSON-LD block.
Frequently asked questions
Should a Shopify apparel product use Product or ProductGroup?
Use `Product` for a simple item with no variants. Use `ProductGroup` whenever size, color, or material variants exist — it lets AI engines cite the right variant for a specific query ('linen shirt in size M') instead of conflating them. Shopify's default Liquid templates emit `Product` only; the upgrade to `ProductGroup` is manual but worth the work for any apparel store with multiple sizes.
Can I emit AggregateRating without reviews visible on the page?
No. Schema must mirror visible content. If you emit `aggregateRating: 4.7 from 32 reviews` but the product page shows no review widget, AI engines and Google both flag it as untrustworthy. Either render the reviews visibly (Shopify Apps like Judge.me or native Shopify Reviews) or drop the schema field entirely.
Should each color variant be a separate `hasVariant` entry?
Yes when the variant has distinct SKU, color, size, image, price, or availability. AI shopping engines answering 'is the linen shirt in black still in stock' need each variant to be a separately-addressable Product node with its own `offers.availability`. Color-only variants get one `hasVariant` per color; size-only get one per size; size+color is the Cartesian product.
Does ProductGroup schema replace Shopify product feeds?
No. JSON-LD on the page complements feeds (Shopify's auto-generated `/products.json`, Google Merchant feed, Meta Catalog). AI shopping engines crawl pages directly *and* read feeds — both signals matter. Don't drop one for the other.
Related resources
Fashion Shopify llms.txt template
Pair this Product schema with an llms.txt content map — both signals work together for AI shopping citation.
Beauty Shopify llms.txt template
Sibling vertical — same JSON-LD principles apply to beauty Product schema, but with ingredient-context fields instead of size/color.
Electronics Shopify llms.txt template
Sibling vertical — for electronics, use ProductGroup with model-number + compatibility fields instead of size/color variants.
Shopify AI Visibility Optimizer
The full AI-visibility stack — schema, content map, crawler policy, citation monitoring.
llms.txt for Shopify — full guide
Background on the content-map signal that pairs with the schema signal in this example.