Before you build an API or a machine-readable endpoint, find two things: which route the agent used to learn about your product, and which field in that route lost the fact. Most failures are fixed by putting the fact, with its condition, into your page text and into the field that route already carries.
The platforms say as much. Google says AI Overviews and AI Mode need no new machine-readable files, AI text files or special markup. Shopify says Shopify Catalog, not its agent discovery files, is the authoritative product feed for agentic channels.
Build an API only when the answer changes per request, or when the agent has to act (cart, checkout) and your platform doesn’t already provide that. The decision tree below is our proposal for telling those cases apart.
Routes, not “agents”
“Can AI read my site?” is the wrong question, because there isn’t one reader. Each platform documents its own paths in:
| Route | Who documents it | What it carries | Can you change it directly? |
|---|---|---|---|
| Open web: your HTML page | Google (AI Overviews, AI Mode); OpenAI says ChatGPT can crawl sites | Visible text, structured data | Yes |
| Shopify Catalog | Shopify (ChatGPT, Copilot and other agentic channels) | Title, description, options, images, price, availability, plus fields Shopify generates and marks “Inferred” | Partly, through product data and Shopify Catalog Mapping |
| Merchant Center feed | Feed attributes, shipping, returns | Yes | |
| Direct product feed | OpenAI (by application) | The fields in OpenAI’s feed spec | Yes, if approved |
| Protocol endpoints (UCP, ACP) | Google, Shopify, OpenAI | Live catalog lookups, carts, checkout | Usually through your platform |
Blocking AI crawlers in robots.txt affects only the first row. Shopify says it doesn’t stop Shopify Catalog from sending your data to the agentic storefronts you’ve activated.
The paired output: one product, four routes
Here is a real product: position 6 in our October 26, 2026 Shopify Catalog search for “humidifier for dry winter air large room quiet top fill”. Store name withheld. We lined up the same three facts across four places an agent could read them.
| Where we read it | Noise | Room size | Runtime |
|---|---|---|---|
| Product page, visible text (fetched without JavaScript) | “as low as 26dB (whisper-quiet)” | “215-430 ft2” (and “20-40 m2”) | “Up to 60 hours on low mist setting” |
Page structured data (JSON-LD description) |
Not stated | Not stated | Not stated |
Store’s product JSON (body_html) |
Not stated | Not stated | Not stated |
Shopify Catalog description |
Not stated | Not stated | Not stated |
| Shopify Catalog generated spec list (marked Inferred) | “As low as 26 dB” | “Up to 430 sq ft” | “Up to 60 hours” |
The facts were on the page all along, in plain HTML. Every structured copy carried the same two-sentence marketing description instead. Shopify’s generated spec list filled the gap, but it dropped two things on the way: the lower room bound (215) and the condition on runtime (“on low mist setting”).
So a shopper with a 200 sq ft bedroom, or one who runs the unit on high, gets a less accurate record than the page gives. That’s not an access problem an API would solve. The structured fields simply don’t contain the facts.
This matters because, in this example, the description was the text all three structured copies shared. In our humidifier search, a decibel figure appeared in the description of 4 of 10 listings (positions 2, 3, 5 and 7). Counting the description or Shopify-generated metadata, it was 6 of 10 (adding 6 and 9). No title had one. In our simulation, an invented humidifier with vague copy was almost never picked from supplied snippets: 3 of 180 Claude sessions, 0 of 60 on GPT-6.1-Sol, 6 of 60 on Gemini 3.8 Flash, 3 of 54 on Gemini 3.1 Pro, against a 25% random baseline. With its facts as a spec line it was picked in 134 of 180, 20 of 60, 19 of 59 and 15 of 55; on the GPT and Gemini models that was every session whose detailed brief asked for what it stated (20 of 20, 19 of 19, 15 of 15), and none with a one-line ask or no shopper. That was a simulation, not live ChatGPT or Gemini. The lesson: vague copy gets excluded, facts get you considered, and you win when your facts answer a stated need that competitors’ listings don’t.
The smallest fix for position 6: add one line to the product description, such as “Noise as low as 26 dB; covers 215–430 sq ft; up to 60 hours per fill on low mist.” The JSON-LD, the product JSON and the catalog description all carried that same text, so it’s the field to fix first. No endpoint required. Then recheck the catalog record after its next refresh, because Shopify marks the catalog description Inferred too.
The decision tree
Start from one failure you can name: an agent, a product, a fact it got wrong or left out. Then answer in order and stop at the first fix.
| Step | Question | If no | If yes |
|---|---|---|---|
| 1 | Is the product in the route at all? | Eligibility fix: Shopify Catalog eligibility, Merchant Center approval, indexing and snippet eligibility for Google. No API helps an ineligible product | Go to 2 |
| 2 | Is the fact on your product page as visible text, with its unit and condition? | Content fix: write it on the page. Google asks for important content in text form | Go to 3 |
| 3 | Is it in the field the route reads (description, feed attribute, structured data)? | Mapping fix: move it into the description, map custom fields with Shopify Catalog Mapping, add the feed attribute, or align JSON-LD with the visible text | Go to 4 |
| 4 | Does the received copy keep it intact? | Authoring fix: put the fact and its condition early in merchant-written text, so a generated or shortened copy has less to rewrite. Recheck after the next refresh | Go to 5 |
| 5 | Is the value current? | Freshness fix: feed cadence and sync. Our freshness guide covers it | Go to 6 |
| 6 | Does the answer change per request, or must the agent act (cart, checkout)? | Stop. You don’t need an API for this failure | Endpoint fix: use your platform’s protocol endpoint (UCP, ACP) first; build your own only if the platform can’t |
Most failures stop at step 2 or 3. Step 6 is real, but narrow. Live stock by location, a quote that depends on the buyer’s address, a configurable price, a cart: these change per request, so a static page or feed can’t hold them. Even then, check what your platform already serves. In our UCP guide, all four Shopify stores we checked already published a UCP profile listing cart and checkout.
Fixes that look bigger than they are
| Fix you’re tempted to build | What the platform docs say | Smaller fix to try first |
|---|---|---|
A custom llms.txt or AI text file |
Google: not needed for AI features. Shopify: stores already serve /agents.md, /llms.txt and /llms-full.txt, and these don’t replace Shopify Catalog |
Fix the product description and feed fields |
| Special schema.org markup for AI | Google: no special structured data is needed; keep structured data matching visible text | Make your existing JSON-LD match the page |
| A public product API | Shopify: Catalog is the primary route to agentic storefronts. OpenAI: a feed isn’t required if ChatGPT crawls you, but gives “greater control” | Map the right fields into the catalog or feed you already have |
| A JSON “twin” of each page | Not documented as a ranking factor by any platform we read | Only as a verification copy with the same facts as the visible page. Our machine-readable data guide covers that |
| Shipping and returns endpoint for Google | Google’s Store Quality help: offer-level shipping data overrides account-level data and should include both cost and transit time | Complete the shipping fields in Merchant Center |
Run the paired check on your own product
- Pick one product and three facts your customers ask about, each with its unit and condition.
- Read the page as text. Fetch it without JavaScript, or use “view source”, and find each fact. If it only appears after a click or a script, note that.
- Read the structured copies. Your JSON-LD
descriptionand any product attributes; on Shopify, the product’s.jsonURL. On Google, your Merchant Center product data. - Read the received record, if you can see one. For Shopify Catalog, compare the description with the generated lists, and quote the field each value came from.
- Fill the table. One row per place, one column per fact. Mark “Not stated”, “Stated”, or “Changed” (quote what changed).
- Fix the highest row that fails. Usually that’s the description field, which every row below it copies.
A blank you can copy:
| Where you read it | Fact 1 | Fact 2 | Fact 3 |
|---|---|---|---|
| Page, visible text | |||
| Structured data / product JSON | |||
| Feed or catalog description | |||
| Generated or received fields |
If all four rows agree and the agent still gets it wrong, you’ve found something worth a deeper look: a shortened copy, a stale feed, or a fact that changes per request. Our evidence-graph guide helps you trace each value to its source, and our parent guide puts this step in order with the rest.
How we checked
On October 27, 2026 we fetched position 6’s product page with a plain HTTP request (no JavaScript), extracted the visible text and the three JSON-LD blocks, and fetched the store’s public product JSON. We searched each for the noise, room-size and runtime statements. We compared them with the Shopify Catalog record saved on October 26, 2026 for “humidifier for dry winter air large room quiet top fill” (top 10, no buyer context): the description field and the generated metadata.tech_specs list.
The visible-text figures appear in a feature list and a specifications table on the page. None of the JSON-LD blocks, the product JSON or the catalog description contained a decibel figure, “430” or “60 hours”. We didn’t test the product or see what any assistant retrieved.