Elena runs a kitchenware store, and by the standards of this series, she's ahead of almost everyone. Her robots.txt welcomes every AI crawler by name. Her structured data ships server-side — run curl against her product pages and the JSON-LD comes back in the raw response, exactly as the delivered-layer audit demands. Access: open. Delivery: clean.
And when a shopping agent was asked for "a carbon steel wok, flat bottom, under $80, in stock" — a question she can answer with three products — it recommended two competitors and a marketplace listing.
Her markup was there. It just wasn't enough. The delivered record said, in effect: a wok exists, it has a name, here is a price that may or may not be current, availability is "InStock" the way it's been "InStock" since the theme was installed, and as for which wok this is in the universe of woks — no identifier, no way to check.
An engine composing an answer it will sign with citations has two options with a record like that: guess, or skip. This article is about why they always skip — and about the three attributes that decide it: identity, availability, and price. This is layer three of the visibility stack — access, delivery, and now legibility — and it's the layer where technically clean stores quietly lose.
(Layer recap for new readers: layer one is whether crawlers can reach you; layer two is whether your data ships in the raw response; this piece is layer three — whether delivered data is rich enough to act on. Files 01–03 cover the first two.)
Why machines skip instead of guessing
Understand the engine's position and everything else follows.
A human shopper fills gaps automatically. No stock indicator? Probably available. Price looks slightly off? Close enough to click. Can't tell if this is the 12" or the 14"? Click in and find out. Humans resolve ambiguity by investigating.
An answer engine resolves ambiguity by selecting different sources. It's assembling a response it will attribute — prices it quotes, availability it asserts, links it stands behind. A wrong guess isn't a bounce; it's a broken answer with the engine's name on it. So candidate records compete not just on relevance but on answerability: can every claim the answer needs be made from this record without inference?
That's the whole mechanic. Your product page isn't being judged like a webpage. It's being judged like a database row — and rows with nulls in the key columns don't survive the join.
Three columns matter more than everything else combined.
FIG.02 — The three key columns. Your product page is judged like a database row, and rows with nulls in key columns do not survive the join.
Identity: the attribute that makes you checkable
What machines need: a stable, global identifier — GTIN (the barcode number), MPN plus brand, or both — declared in your structured data as gtin/mpn/brand on the Product.
Why it's decisive: an identifier is how a machine resolves this listing to a known product in the world. With a GTIN, an engine can reconcile your listing against manufacturer data, other retailers, review corpora, and shopping feeds — every cross-reference that raises confidence enough to cite you. Without one, your product is an island: a string of words that might be the same wok as the one on three other sites, or might not. Google's Merchant Center has required unique product identifiers for exactly this reason for years; answer engines inherited the logic and raised the stakes.
How Shopify stores fail it: the identifier usually exists — it's the Barcode field on the variant — but it's empty for half the catalog, filled with internal SKUs that mean nothing globally, or never mapped into the JSON-LD by the theme. And for genuinely GTIN-less products (handmade, custom), the correct move is declaring brand + MPN and, where feeds are involved, flagging the identifier's absence honestly rather than inventing one. A fabricated GTIN is worse than none: it's a checkable lie, and engines check.
Availability: the attribute where wrong beats absent — downward
What machines need: an availability value from the schema.org enum — InStock, OutOfStock, PreOrder, BackOrder, LimitedAvailability — that is bound to inventory, not typed into a template.
Why it's decisive: availability is the one field where the answer's usefulness collapses entirely if it's wrong. An agent that says "in stock at Elena's" about a sold-out product has failed its user at the exact moment of action. Engines therefore treat availability signals the way you'd treat a witness: one demonstrated falsehood and everything else the record says gets discounted. Gap class 2 from the delivered-layer teardown — "InStock" hardcoded as a literal string — is this failure at scale: not missing data, confidently wrong data, on every sold-out product you have, forever.
How Shopify stores fail it: the theme emits a fixed string instead of deriving from product.available / variant inventory; or availability is declared once for the product while variants sell out individually; or preorder and backorder states get flattened to InStock because the enum was never wired.
Price: the attribute agents cross-examine
What machines need: price and priceCurrency that match what a buyer will actually pay, per variant, with priceValidUntil where sales apply.
Why it's decisive: price is the claim most likely to be quoted verbatim in an answer — which means it's the claim engines verify hardest. When the markup says 64.00, the rendered page shows $49 after a discount script, and a feed somewhere says $52, the discrepancy doesn't get adjudicated in your favor. Conflicting testimony gets the whole witness dismissed. And currency omission is its own quiet killer: a bare "price": "49.00" with no priceCurrency is unanswerable for an agent comparing across borders.
How Shopify stores fail it: currency-converter apps rewriting display prices client-side while markup holds base currency; sale logic in JavaScript with priceValidUntil never set; bundle pricing that exists nowhere in structured form.
The multiplier: all three, per variant
Here's what turns three small gaps into systematic invisibility. Identity, availability, and price aren't product-level facts — they're variant-level facts. The 12" wok and the 14" wok have different GTINs, different stock states, different prices. A catalog that declares one Offer for a thirty-variant product hasn't summarized the truth; it's replaced thirty answerable records with one unanswerable one. "Does the flat-bottom 14-inch come in under $80, in stock?" has a real answer in your inventory system — and no answer in your markup.
That's gap class 4 seen from the machine's side: variant collapse isn't a markup style choice, it's the difference between a catalog an agent can query and a brochure it can only skim.
FIG.03 — Variant collapse, counted. Thirty stock states and thirty prices arrive at the machine as one.
The fifteen-minute audit
FIG.04 — Three greps, three verdicts. Identity coverage, availability truth, offers per variant — fifteen minutes, no tooling.
CHECK 01 / IDENTITY COVERAGE. In Shopify admin, export products and look at the Barcode column — or eyeball your top twenty sellers. Empty, or filled with internal SKUs? That's your identity gap, quantified. Then confirm what actually ships:
curl -s https://yourstore.com/products/your-best-seller \
| grep -oE '"(gtin13?|gtin14|gtin8|mpn|brand)"[^,}]*'
Nothing back while barcodes exist in admin means the theme never maps them — data you own, invisible to machines.
CHECK 02 / AVAILABILITY TRUTH TEST. Find one sold-out product (or set one variant to zero inventory) and pull its delivered record:
curl -s https://yourstore.com/products/that-product \
| grep -o '"availability"[^,}]*'
If it says InStock, your availability is a template string, not a fact — and every answer engine that's compared it against reality now has a reason to distrust the rest of your markup.
CHECK 03 / OFFER-PER-VARIANT COUNT. One number tells you whether variants are declared or collapsed:
curl -s https://yourstore.com/products/your-most-varianted-product \
| grep -c '"@type":[[:space:]]*"Offer"'
Compare against the variant count in admin. 1 against thirty variants is twenty-nine questions your catalog can't answer.
The remediation order mirrors the audit: map existing barcodes into the markup (data you already own is the cheapest legibility you'll ever buy), bind availability to inventory state with the full enum, declare offers per variant with currency, and only then worry about enrichment beyond the big three.
Complete answers come from complete records
The series so far, as one sentence per layer: open the door (FILE 01), ship the data in the response (FILE 02), and make the record rich enough that an engine can build its answer from your row without guessing — because engines that cite don't guess, they skip.
What's left is the frame that holds all of it: search, answers, generation, and agents are four different machine audiences with four different demands, and most of the confusion in this space comes from optimizing for one while being judged by another. Naming those four cleanly — and showing where each of these layers serves which audience — is the next file.
Elena's fix, for the record: her barcodes were in admin all along — eleven hundred products, ninety percent coverage, mapped to nothing. One template change shipped six years of identity data she already owned. The wok question now names her store, quotes the right price, and gets the stock state correct — because for the first time, the machine could check.
Sources & further reading
- schema.org — Product, Offer, and ItemAvailability definitions: https://schema.org/Offer
- Google — Product structured data & unique product identifier requirements: https://developers.google.com/search/docs/appearance/structured-data/product
- Google Merchant Center — Unique product identifiers (GTIN, MPN, brand): https://support.google.com/merchants/answer/160161
- Shopify — Product variant data and barcode fields: https://help.shopify.com/en/manual/products/variants
- Rank Sniper Field Notes — FILE 01, robots.txt: /blog/robots-txt-ai-crawlers-shopify · FILE 02, declared vs delivered: /blog/ai-agent-declared-vs-delivered-product-page · FILE 03, the invisible channel: /blog/shopify-store-invisible-ai-buyers
Rank Sniper — Field Notes. Catalog legibility and AI-visibility verification for Shopify. We verify what AI agents actually receive from your store; we don't generate content and hope. Verifier, not generator.
