Your product page says $179. ChatGPT says $199. Both numbers came from your store — the page you updated on Tuesday, and the JSON-LD block your theme generated when the product launched. The AI buyer did not hallucinate. It quoted your own data layer, and that layer is out of date.
Stale structured data is the worst state a store can be in, because it is the only one where being machine-readable actively hurts you. A store with no JSON-LD gets skipped — quietly, and the fix is obvious. A store whose JSON-LD contradicts its own page gets quoted. The model repeats the old price or the old stock status in its recommendation, the shopper clicks through, and your site shows a different number than the assistant gave. Nobody blames the model. They blame the store. The fix is not more fields — it is three fields used correctly, plus one rule: the two layers must come from the same source, and the old price must expire.
How the drift happens
A product page carries two layers that are supposed to say the same thing: the visible HTML a person reads, and the JSON-LD Product block an AI buyer reads. They drift because they are born at different moments. The visible price renders from the live catalog on every page load — or nearly every load. The JSON-LD is frequently generated once: by an app at installation, by a theme at product launch, or by a developer who pasted a template block and never revisited it. Then a sale ends, the catalog price changes, a product sells out. The page updates. The block does not.
Caching widens the gap. Product pages sit behind CDNs and full-page caches, and a price change can take hours to reach the rendered page — on a schedule that is not necessarily the same as the JSON-LD's. Two layers, two refresh cycles, one page. Drift is not a bug someone forgot to fix once. It is the steady state of any store that does not generate both layers from the same source at render time.
The AI buyer quotes. It does not verify.
When an AI buyer recommends a product, it treats the machine-readable fields as the authoritative description of current state — that is the entire point of structured data, and it is why a well-formed block beats prose. The model does not compare your JSON-LD against your rendered HTML and flag the difference, and it does not call your checkout to confirm the number. It reads price and availability, takes them as fact, and quotes them.
The quote outlives the request. A shopper copies the recommendation into a note or a group chat. The assistant re-uses the fetched data in a later summary without fetching the page again. A stale price does not surface once — it becomes part of the record the model keeps about your product until the next crawl, whenever that is.
Stock drift is sharper than price drift. A block that still says InStock on a product that sold out yesterday gets your store recommended for a purchase that cannot be completed. A wrong price creates a complaint. A wrong availability creates a dead end, and dead ends are what make a shopper abandon the assistant's list entirely.
The mismatch lands on your tab
When the numbers disagree, the shopper does not conclude that the model is careless. The shopper concludes that the store is unreliable. If the AI quotes a price higher than your page shows, the surprise is pleasant — until the shopper wonders what else the model got wrong about you. If it quotes a price lower than your page shows — an expired sale, a promo that ended — the experience reads as bait-and-switch, which is exactly the accusation your store did not deserve and cannot answer in the moment. Either direction, the evidence trail the assistant presents points at you.
This failure mode is not new; it is just newly visible. Google's structured data guidelines have required for years that machine-readable data accurately reflect what the page shows, and Merchant Center disapproves listings whose feed price disagrees with the landing page. The rule exists because the gap costs sales. On the ad side there is a disapproval queue that catches the mismatch. The AI buyer has no queue — it just quotes, and the mismatch ships to the shopper directly.
Three fields that keep the layers honest
1. priceValidUntil. Schema.org defines this on Offer: the date after which the price is no longer valid (spec). It is the expiration date for your number. A crawler that respects schema semantics can see that the $199 it fetched is only valid until Friday, and treat anything after that as unknown rather than fact. Most stores never set it, which is why a launch-day price can be quoted months later with full confidence. Add it — and regenerate it: today plus the duration of the current pricing rule, not a constant typed once.
2. Availability from live inventory, not a template default. Many product templates hardcode InStock for every product. When the last unit sells, the page renders "Sold out" while the block keeps insisting otherwise. The block must be emitted from the same inventory query that decides what the shopper sees. If the store can show the stock status, it can say it (spec).
3. One source, two outputs. The durable fix for all drift is to render the visible price and the JSON-LD from the same catalog object in the same render pass. Then the two layers can only disagree if the cache disagrees with itself. This is a template change, not a replatform — most e-commerce platforms expose the same product object to both the HTML template and the structured data block, and the fix is to point both at it.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Fenwick Waxed Barn Jacket",
"offers": {
"@type": "Offer",
"price": "179.00",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"priceValidUntil": "2026-09-14",
"url": "https://example.com/barn-jacket"
}
}
</script>
priceValidUntil takes an ISO date and it must move every time the pricing rule changes. A priceValidUntil from last season is just another stale number — present, plausible, wrong.
For the field-level view of what AI buyers extract, see the eight Product schema fields that decide whether AI recommends you. For the scoring logic behind all three dimensions, see the methodology.
The ten-minute drift audit
Open your three best-selling product pages and view source. Then:
- Compare the visible price with
pricein the JSON-LD block. Any difference, in either direction, is a live problem. - Check
availabilityagainst what the page shows.InStockon a sold-out page is the dead-end failure. - Look for
priceValidUntil. Absent is the default. Present but past is the trap. - If you find drift, find where the block is generated. A pasted template or an app-generated block should be replaced with a render-time block from the catalog.
The stores that win AI recommendations are not the ones with the most elaborate markup — they are the ones whose data the model can quote without checking, and without being wrong. See where your store stands: scan it free at prefero.me.