Structured product data for AI shopping agents
How to give AI shopping agents complete, machine-readable product data: the schema.org Product and Offer fields that matter, how to mark up sizes and colours with ProductGroup, and a copy-ready JSON-LD example.
Short answer: put a schema.org Product in JSON-LD on every product page, with an Offer that states the price, currency and stock status, plus an image, a brand and at least one identifier (gtin, sku or mpn). If the product comes in sizes or colours, publish it as a ProductGroup with one Product per variant. AI shopping agents read this data to compare, recommend and buy; without it they have to guess from your page layout.
Check your product pages with the free agent-readiness audit. Structured data is the biggest single category in the score.
Why structured data matters more for agents than for search
A search engine can still rank a page with patchy markup. An agent comparing ten stores for “waterproof trail boots, size 9, under £120” needs to know, for certain, the price, currency, whether size 9 is in stock and what the product is. If any of that is missing or only shown visually, the agent either skips your store or gives the shopper a wrong answer.
The fields that matter
| Field | Where | Why agents need it |
|---|---|---|
name |
Product | Matching the shopper’s request |
description |
Product | Understanding what the product is |
image |
Product | Showing the product back to the shopper |
brand |
Product | Brand searches and comparisons |
gtin / gtin13, sku, mpn |
Product | Identifying the exact item across stores |
price |
Offer | Comparing and filtering on price |
priceCurrency |
Offer | A price without a currency is ambiguous |
availability |
Offer | Not recommending things that are out of stock |
Price, currency, availability and an identifier are the most important. A GTIN (the barcode number) is best because it identifies the same item at every retailer.
A minimal complete example
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Ridge waterproof trail boot",
"description": "Leather trail boot with a waterproof membrane and a Vibram sole.",
"image": ["https://yourstore.example/images/ridge-boot.jpg"],
"brand": { "@type": "Brand", "name": "Ridgeline" },
"sku": "RIDGE-BRN",
"gtin13": "5012345678900",
"offers": {
"@type": "Offer",
"url": "https://yourstore.example/products/ridge-boot",
"price": "119.00",
"priceCurrency": "GBP",
"availability": "https://schema.org/InStock",
"itemCondition": "https://schema.org/NewCondition"
}
}
Put it in a <script type="application/ld+json"> tag in the page’s HTML. It must be in the HTML the server sends, not added later by JavaScript, because many agents don’t run scripts.
Sizes and colours: use ProductGroup
A dropdown of sizes is invisible to most agents. Describe each variant as its own Product inside a ProductGroup:
{
"@context": "https://schema.org",
"@type": "ProductGroup",
"name": "Ridge waterproof trail boot",
"productGroupID": "RIDGE",
"variesBy": ["https://schema.org/size", "https://schema.org/color"],
"brand": { "@type": "Brand", "name": "Ridgeline" },
"hasVariant": [
{
"@type": "Product",
"name": "Ridge waterproof trail boot, brown, UK 9",
"sku": "RIDGE-BRN-9",
"size": "UK 9",
"color": "Brown",
"offers": { "@type": "Offer", "price": "119.00", "priceCurrency": "GBP", "availability": "https://schema.org/InStock" }
},
{
"@type": "Product",
"name": "Ridge waterproof trail boot, brown, UK 10",
"sku": "RIDGE-BRN-10",
"size": "UK 10",
"color": "Brown",
"offers": { "@type": "Offer", "price": "119.00", "priceCurrency": "GBP", "availability": "https://schema.org/OutOfStock" }
}
]
}
Each variant has its own sku, price and availability, so an agent can answer “is it in stock in a 10?” correctly.
Platform notes
WooCommerce
WooCommerce outputs basic Product JSON-LD, but variable products usually list a price range rather than each variation, and GTINs are often missing. Add the GTIN field (WooCommerce has a built-in “GTIN, UPC, EAN or ISBN” field in recent versions) and use an SEO or schema plugin that outputs ProductGroup and hasVariant for variable products.
Magento / Adobe Commerce
Many Magento themes use microdata rather than JSON-LD, and configurable products keep their options in swatch JavaScript. Add JSON-LD with an extension or in the product view template, and output each child product as a variant.
Custom stores
Generate the JSON-LD on the server from the same data that renders the page, so price and stock can never disagree with what the shopper sees.
Common mistakes
- Price without currency, or a price formatted as text such as
"£119". Use"price": "119.00"and"priceCurrency": "GBP". - Availability as plain text such as
"In stock". Use the schema.org URL, for examplehttps://schema.org/InStock. - Invalid JSON, often from an unescaped quote in a product description, which makes the whole block unreadable.
- Markup added by JavaScript after the page loads.
- Stale data: a cached page that still says
InStockafter the item has sold out.
How to test it
Run the free agent-readiness audit. It samples up to five product pages and reports which fields are missing on how many of them, whether variants are machine-readable, and whether any JSON-LD block fails to parse. For a single page, Google’s Rich Results Test and the Schema.org validator are also useful.