Learn / Fixes

How to add product schema for AI agents

Product schema is how you state your price, availability, identifier and terms as data rather than as layout, so an agent reading your page does not have to infer them. Adding it is usually a template change rather than a redesign, and the test of success is not that the markup validates but that the specific facts an agent needs are present in it.

Product schema is how you state your price, availability, identifier and terms as data rather than leaving an agent to infer them from your layout. Adding it is normally a template change rather than a redesign, and the useful measure of success is not that the markup validates but that the specific facts an agent needs are actually in it.

This is the fix for missing product schema and, in most stores, for missing price data as well.

The fields that decide the outcome

A Product object can carry a great deal. Four fields do nearly all the work, and a store that gets these right and nothing else is in good shape.

  1. price and priceCurrency, on an Offer. Without these you are not comparable, only visible.
  2. availability, on the same Offer, and correct when the answer is no rather than only when it is yes.
  3. An identifier, ideally a GTIN, so you can be matched to the same product elsewhere. See how to add GTINs to your catalogue.
  4. Variant level data, so a size or colour has its own price and availability rather than inheriting the parent’s. See no variant data.

A rendered price is not a published price

The failure worth dwelling on is the one where everything looks correct. Your page shows the right price, because a script calculated it after load. Your schema block carries a different number, because it was populated from a value that was correct when the template was built.

Every human who checks sees the correct price. Every agent reads the other one. If the schema price is the list price and the page shows the sale price, you are competing on your worst number, silently, in every comparison you enter.

How to check what you actually emit

Fetch the page rather than inspecting it in your browser, because the browser shows you the result after scripts have run and the whole question is what exists before that.

  1. Request the product URL and read the served markup directly. A schema block injected after load is not there for an agent that stopped at the markup.
  2. Find the JSON-LD block and read the four fields above. Do not check that they exist, check that they are right.
  3. Repeat on a product that is out of stock, and on one with several variants. Both are where the defects live, and neither is the product anyone tests with.
  4. Compare the schema price against the price the page displays. If they disagree, that is the finding.

What this does not fix

Schema makes your product legible. It does not make your store discoverable, and it does not make your checkout work. An agent that cannot fetch your page never sees your schema, so if your bot rules are blocking, fix that first: see robots blocks agent.

For where this sits in the wider sequence, see the agentic readiness checklist.

Questions

My theme already outputs product schema. Is that enough?

Often not. Many themes emit a valid Product object with the name and image and leave price or availability out, or fill them from a value that is only correct at build time. Valid markup and useful markup are different tests. Check the emitted output on a real product rather than trusting that the feature exists.

Does the price in my schema have to match the price on the page?

Yes, and this is a common quiet failure. If a discount is applied by script at render and your schema still carries the list price, an agent comparing you uses the higher number. You lose comparisons you would have won, and nothing about the page looks wrong.

Should I use JSON-LD or microdata?

JSON-LD, in almost every case. It sits in one block, survives template changes better than attributes scattered through markup, and does not tie your data to your layout. The one thing that matters more than the format is that the block is present in the served markup rather than injected after load.

Scan your store