Audit your catalog.search + catalog.lookup responses
Thirty-three rules across variant data, product completeness, pricing consistency, response envelope, and cross-capability round-trips. Tests what your catalog endpoints actually return — the difference between "manifest validates" and "an agent can buy from you." Enter your domain to probe live, or paste a catalog response for client-side audit.
What we audit
Variant data 7 rules
- Variants carry
options[]when multi-variant - Each
selected_optionhas bothnameandlabel - One axis per
selected_optionentry - Consistent labels across sibling variants
availabilitywithavailable+statusproduct.options[].valuesnon-emptyproduct.optionsaxes match variants
Product completeness 13 rules
- Required product fields (
id,title, …) - Required variant fields (
id,title,price, …) variants[]non-empty (specminItems: 1)descriptionobject withplain/html/markdownmedia[]entries have requiredtype+urlcategories[]entries havevaluemetadatanot misused as single-value optionsurl,categories[]presence
Pricing consistency 6 rules
- Every price has
amount+currency amountis an integer (ISO 4217 minor units)currencymatches^[A-Z]{3}$price_range.min≤price_range.max- Currency consistent across range + variants
- Variant prices within product range
Response envelope 4 rules
ucp.versionpresent + known- Capability echoed in response
products[]is an array
Cross-capability 3 rules
- Search → lookup round-trip by
id - Idempotency — same query, same products
- Latency under agent timeout budget
Audit rules are derived from the UCP 2026-08-25 specification and the failure modes documented in UCP Variant Data: The #1 Reason Agent Checkouts Fail.
Audited against the live spec
Spec-version distribution across 18,314 verified merchants.
2026-08-25
18,169 stores
latest 2026-04-08
115 stores
2026-01-11
14 stores
2026-01-23
13 stores
How to Audit Your UCP Catalog
Find your catalog endpoint
Your /.well-known/ucp manifest declares it. Look for dev.ucp.shopping.catalog.search under capabilities, or the service endpoint under services.dev.ucp.shopping. The validator resolves this automatically when you enter a domain — it handles both REST and MCP transports.
Run the audit
Enter your domain to probe live (the validator POSTs a search query to your catalog endpoint, optionally calls catalog.lookup for a round-trip, and re-runs the search for an idempotency check). Or paste a catalog response JSON for client-side rule evaluation only.
Fix failures first
Failures are spec violations — missing required fields, malformed shapes, variants[] with minItems: 0, or descriptions that aren't objects per v2026-08-25. Agents trip on these. Warnings are optional improvements that lower agent intelligibility but don't block transactions.
Re-audit + monitor
Re-run after each change — the rule engine is fast enough to use in a tight dev loop. Once the audit is clean, verify the live endpoint with the UCP Checker for HTTP-layer signals (latency, robots.txt, AI bot policies), and set up UCP Alerts to catch regressions.
Common Catalog Audit Failures and How to Fix Them
The rule data behind these comes from the UCP 2026-08-25 schemas — product.json, variant.json, description.json, and the catalog capability spec. Most failures cluster in two shapes: missing required structure, and descriptions/variants that violate minItems / minProperties.
Failures (spec violations)
Agents either skip the product, fail the cart call, or stop mid-flow. Fix these before any warnings.
| Rule | What's broken | Fix |
|---|---|---|
product-required-fields | Missing id, title, description, price_range, or variants on a product | Populate every required field listed in product.json's required array. None is optional. |
variants-non-empty | variants[] empty or not an array (spec minItems: 1) | Every product must ship at least one variant. Even single-variant simple products should declare a single variant with id/title/description/price. |
description-is-object | description returned as a string or other non-object | The v2026-08-25 spec requires description to be an object with at least one of plain, html, or markdown. Raw strings are legacy and out of spec. |
description-non-empty-object | description: {} (empty object) | Populate at least one of plain / html / markdown — description.json declares minProperties: 1. |
product-options-variant-cardinality | Declared axes in product.options[] don't match what variants actually carry | Either every declared axis has variants honouring it, or drop the axis from product.options[]. Dangling axes confuse strict agents into null matches. |
price-range-valid | price_range.min > price_range.max | Swap them. Agents quoting the range can't reliably price the product when min exceeds max. |
currency-consistent | Mixed currencies across price_range and variant prices | Normalise to one currency per product response. Localise via separate locale-aware endpoints if you support multi-currency. |
variant-price-in-range | A variant's price.amount is outside price_range.min–max | Either widen price_range or correct the variant price. Misalignment causes agents quoting the range to misrepresent at least one variant. |
search-lookup-roundtrip | A product returned by catalog.search can't be re-fetched by catalog.lookup using its id | The two endpoints must share the same id space. Common causes: lookup uses a different id field (e.g. product_id vs id), or lookup returns a different product entirely. |
Warnings (recommendations)
Spec-optional fields that materially affect how agents interpret your catalog. The audit will still pass overall.
| Rule | What's missing | Why it matters |
|---|---|---|
variant-availability-complete | availability.status not set, or set to a non-standard value | Without status, agents can't decide between substituting, waiting, or surfacing an out-of-stock message. Well-known values: in_stock, backorder, preorder, out_of_stock, discontinued. |
variant-options-no-conflation | Slash- or ampersand-joined values like "Medium / Regular Fit" in a single selected_option.label | Split conflated axes into their own selected_option entries. Different agents parse slash-joined labels inconsistently. See the variant guide. |
description-plain-present | description.plain not provided (only html or markdown) | plain is what agents render in chat responses. Missing it forces the agent to strip HTML or skip the description, lowering response quality. |
metadata-not-misused-as-option | Single-value product.options on single-variant products (e.g. "Color": "Gray" with one variant) | Move descriptive attributes to metadata.attributes. Single-value option pickers look selectable but aren't, misleading consumer UIs. |
media-present | media[] empty or absent | Agents have nothing visual to surface in product cards or visual confirmation steps. The first item is treated as the featured media. |
capability-echoed | Response doesn't echo dev.ucp.shopping.catalog.search in ucp.capabilities | Echoing the called capability in the response envelope lets agents confirm spec-version compatibility at the response level, not just from the manifest. |
search-idempotency | The same search query returns different product ids on retry | Either ordering isn't stable, or per-request randomness is leaking. Both confuse agents trying to refer back to earlier results. |
response-time-under-budget | catalog.search takes 1.5–3 seconds | Inside most agent timeout budgets but close to the edge. Multi-call flows (search → lookup → cart) compound latency; tightening helps them complete. |
Which AI Agents Call Your Catalog?
UCP manifests are the discovery layer; catalog endpoints are the conversion layer. These are the agents that fetch catalog.search and catalog.lookup in production:
Google AI Mode + Search
Powers UCP checkout in AI Mode and main Search results. Calls catalog.search over both REST and MCP, depending on the merchant's declared transport.
ChatGPT / OpenAI
Shopping flows in ChatGPT discover stores via UCP and fetch catalog data over MCP. Variant-shape problems here surface as cart-add failures or wrong-item selections.
Claude / Anthropic
Claude's commerce sessions use MCP tool calls against catalog endpoints. Anthropic's stricter content filters surface inconsistent labels and conflated axes faster than other models.
Microsoft Copilot
Now integrated into the Shopify Agentic Storefronts dashboard alongside ChatGPT. Catalog quality affects Copilot conversion in the same shapes as the others.
Test how each model performs against your catalog with UCP Playground — live agent shopping sessions across 16 frontier models, with replay and step-by-step inspection.
UCP Validator vs. Catalog Validator vs. UCP Checker — Which Do I Need?
UCP Validator
- Audits your
/.well-known/ucpmanifest structure - Required fields, transport bindings, signing keys
- Runs client-side — paste JSON, get instant feedback
- Use during manifest development
Catalog Validator This tool
- Audits what your catalog endpoints actually return
- Variant resolvability, product completeness, pricing, response envelope
- Probes live (REST or MCP) or audits pasted JSON
- Use after your manifest validates but before agents try to shop
UCP Checker
- Audits the live HTTP layer of your manifest endpoint
- Robots.txt, AI bot access, latency, TLS, monitoring
- Stores history for alerts + ecosystem stats
- Use for production verification and regression monitoring
Most stores need all three. The Validator confirms your document is well-formed, the Catalog Validator confirms what it points at is agent-resolvable, and the Checker confirms the whole stack stays healthy in production.
Frequently Asked Questions
What is a UCP catalog validator?
catalog.search and catalog.lookup endpoints against the official Universal Commerce Protocol specification. It checks variant data resolvability, required product fields, pricing consistency, response envelope correctness, and cross-capability round-trips — the substance of whether AI shopping agents can actually transact with your store, not just whether your manifest is well-formed.How is the catalog validator different from the UCP validator?
/.well-known/ucp manifest — the structural document that describes your API surface. The Catalog Validator audits what comes back when an agent actually calls your catalog endpoints — products, variants, options, availability, pricing. Manifests can validate perfectly while catalog responses still break agent shopping. Variant-shape problems are the #1 reason agent checkouts fail in the field.What does the catalog validator check?
ucp wrapper and shape), and Cross-capability (3 on search/lookup round-trips and idempotency). All rule data is derived from the UCP 2026-08-25 schemas — product.json, variant.json, description.json, price.json, amount.json, and friends.Why does my variant data fail the audit when my manifest passes?
variant.options[] entries, conflated axes in a single string, inconsistent labels across siblings, or missing availability flags. These break the cart flow without ever invalidating the manifest. We dig into the failure modes in detail in UCP Variant Data: The #1 Reason Agent Checkouts Fail.Does this work for stores running Shopify, WooCommerce, BigCommerce, Magento, or PrestaShop?
catalog.search and catalog.lookup endpoints actually return, regardless of which commerce stack generates them. Live-domain mode auto-detects whether your catalog runs over REST (typical for WooCommerce, BigCommerce, Magento) or MCP (Shopify's Storefront MCP). Browse adoption stats by platform on the platforms page.Can I audit programmatically?
/api/catalog-validator?domain={domain}&query={query} — it returns the full audit envelope (manifest + search response + optional lookup round-trip + idempotency probe) as JSON. Audit rule logic runs client-side on the same response, so you can either consume the envelope and run your own rules, or scrape the rendered page. Full developer tools and APIs here.What's the difference between a failure and a warning?
variants[] empty when product.json declares minItems: 1. Warnings are spec-optional but agent-useful — the field isn't required by the schema, but its absence makes the data harder for agents to use. Example: availability.status missing (the spec defines five well-known values but doesn't enforce them).