This pack has not completed a verification run yet, so nothing is published here. When the harness runs it, this space becomes the measured record: pass rate as M of N clean-scaffold runs on a pinned model, per-run token cost and wall time, per-check results, locked dependency versions, and whether the scaffold was left pristine. No pass rate, token cost, or deploy is claimed until then.
Product Feed & Merchant Center Compliance
complex-universaldraftA Google Shopping product feed that survives the reviewer: spec-valid RSS 2.0 output validated offline against the transcribed product data spec, a feed-to-landing-page price and availability consistency crawler, GS1-correct GTIN handling with honest identifier_exists semantics, on-page structured data generated from the same source as the feed, and a diagnostic that reports each named disapproval cause — including the one it cannot check.
How install works
- Accounts
- Tools
Accounts + tool install: ~15–20 minutes (most of it is Merchant Center's
Full setup walkthrough ships in the zip after purchase.
The thing that gets your products disapproved is usually not in your feed. The
#1 data-related disapproval cause is the feed disagreeing with the landing page
Google crawls — a mismatch that is invisible to every validator that only looks
at the file, and that no agent builds a check for, because it is not a property
of the feed. This pack builds the whole surface: RSS 2.0 output validated
offline against Google's product data spec shipped as versioned data, a
consistency crawler that compares price, currency, sale window and availability
against your real pages, GS1-correct GTIN handling, honest `identifier_exists`
semantics, and page structured data generated from the same object as the feed
so the two cannot drift. **This pack is currently `draft`: no clean-room receipt
has been published for it yet.** When one is, this line will read `N of M`
clean-room builds passed with all 15 acceptance checks — and until it does,
treat everything below about the build as design intent, not evidence. What is
already true today is that the acceptance suite runs hermetically: no Merchant
Center account, no Google API, no network.
Example use cases
- **A Rails/Django/Next.js store with a custom storefront** that has no
platform-supplied Google channel — the merchant is hand-writing a feed
template and finding out what is wrong from Merchant Center Diagnostics, one
three-day review cycle at a time.
- **An agency running Shopping feeds for a dozen clients** — the same
`feed-doctor` command, wired into each client's CI, turns "the client emailed
saying products vanished" into a build failure on the deploy that caused it.
- **A headless commerce build where prices live in one service and pages render
in another** — exactly the architecture where feed and landing page drift
apart quietly, and exactly the one where a consistency crawler pays for
itself in a week.
- **A handmade/vintage seller with no GTINs** — custom goods, antiques and
pre-1970 books are the case `identifier_exists` exists for, and the case
everyone gets backwards in both directions.
- **A store adding a second target country** — the conditional rules
(apparel attributes, shipping, tax, currency) are country-scoped, and the
pack makes running one pipeline per country a config change rather than a
fork.
Why this pack
No "always" claims — agents are stochastic, Google's rules move, and a passing
check is not an approval. This is what the pack pre-solves, what it costs, and
what you give up.
| Bare agent, no pack | Feed-management SaaS (DataFeedWatch / Productsup / Feedonomics class) | Platform channel app (Shopify "Google & YouTube", BigCommerce equivalent) | Hand-rolled in-house | This pack | |
|---|---|---|---|---|---|
| **Cost** | "Free" (agent time only) | Recurring subscription, commonly scaling with SKU count or channel count | Free, if you are on that platform | Engineering time — days to weeks | $129 one-time |
| **Time to a correct feed** | Unknown. An agent asked to "generate a Google Shopping feed" has no reason to know the landing-page comparison exists | Fast — this is their product, and for a large catalogue on many channels they are genuinely the right answer | Fast, and it is maintained by the platform | Slow — the failure modes are discovered from Diagnostics, not from tests | 2–3 sessions on a $20/mo agent plan, per the pack's own budget (estimate; no receipt yet) |
| **Correctness risk** | High and silent — see the bug classes below | Low on the feed itself; feed↔page consistency depends on which tier and features you buy | Low for a stock storefront; it reads your platform's own product data, so the page and the feed share a source | High until you have independently rediscovered the failure modes below | Bounded by `verify.sh`'s 15 checks, run against a local storefront with planted drift. **No published pass rate yet** |
| **Lock-in** | None, and no guardrails | Real — your transformation rules live in their UI, and leaving means rebuilding them | Real but cheap — you are already on the platform | None | None. Plain TypeScript in your repo, one class to change where your catalogue comes from |
| **Honest verdict** | — | **If you are a large multi-channel retailer, buy the SaaS.** This pack does not replace a feed-management platform | **If you run a stock Shopify or BigCommerce store, use the free official app first.** It is better than this pack for that case | — | For custom and headless storefronts, and for anyone who wants the consistency check inside their own CI rather than inside someone's dashboard |
**What a bare agent typically ships that this pack pre-solves** (specific bug
classes, not a claim that every agent hits every one):
- *Valid XML, invalid feed.* The output parses, the namespace looks right, and
it is non-conforming: an `id` over 50 characters, an `availability` value
Google retired, a `price` with a currency symbol in it, a missing
`availability_date` on a preorder. Well-formedness checks pass all of these.
A near-miss namespace URI (`https://` instead of `http://`) is the sharpest
version — the file parses perfectly and Google ignores **every** `g:`
attribute in it.
- *The consistency check that never gets written.* Price mismatch between feed
and landing page is ranked the **#1** data-related disapproval cause, and
structured-data inconsistency between feed and page markup the **#2**
([Productsup, 2025-12-10](https://www.productsup.com/blog/top-5-reasons-for-google-merchant-center-disapprovals-and-how-to-fix-them-in-2026/)).
Neither is a property of the feed, so an agent reasoning about "is my feed
correct" never gets near them. This pack ships the crawler and a fixture
storefront with planted drift to prove it works.
- *`identifier_exists`, wrong in the expensive direction.* An agent whose loop
is "make the missing-GTIN error go away" sets `identifier_exists: no` on
mass-produced goods. Google downgraded that error from a disapproval to a
**warning** in late 2023, which makes it cheap to get wrong and hard to
notice — the feed is accepted, the products just quietly underperform.
Invalid-GTIN errors were found affecting **48.43% of merchants** (and about
4% of submitted products) in DataFeedWatch's Multichannel Marketing Report
2023, as reported by [Search Engine Land, 2023-10-31](https://searchengineland.com/top-data-errors-that-cause-google-shopping-to-disapprove-products-433993).
- *Structured data that disagrees with the feed it just generated.* The agent
writes the feed, then writes the product page, computing the price a second
time with a second rounding rule — and, when a sale is running, putting the
regular price on the page while the feed advertises the sale price. Both look
right in isolation. This pack makes them two projections of one object, and
the acceptance suite feeds the generated markup back through the checker for
every item to prove they cannot diverge.
- *A checksum-only GTIN validator.* GS1 mod-10 written left-to-right with a
fixed weight is correct for one GTIN length and quietly wrong for the other
three. And a restricted-prefix GTIN (`2…`, `02…`, `04…` — in-store and
variable-measure ranges) is arithmetically **valid**, so a checksum-only
check waves it straight through to a rejection.
Scale envelope
Derived from the shipped architecture and the pinned stack, not from a load
test. Nothing here is receipt-measured; the pack has no receipt yet, and where
a number is an estimate it says so.
- **Feed generation is O(n) string building, in memory.** At a typical ~700 B
to 1.5 KB of XML per item, a 50,000-item feed is roughly 35–75 MB of string —
fine for Node's default heap on a small container. **First ceiling: about
100,000 items**, where the whole-feed-in-memory approach starts to matter more
than anything else in the pipeline. **Estimate.**
- **Upgrade path past that ceiling:** stream the feed instead of building it
(the builder is one function and the `<item>` loop is the only part that
changes), or split by `google_product_category` into several data sources —
Merchant Center accepts multiple. Google's own documented ceiling for a feed
file is far higher (4 GB), so this is a Node ceiling, not a Google one.
- **The crawler is the real constraint, and it is time, not memory.** At the
default concurrency of 4 and a 200 ms page fetch, that is ~20 pages/second:
**10,000 products in roughly 8–9 minutes**, 100,000 in about 1.4 hours.
**Estimate — your page latency is the whole variable.**
- **Upgrade path for the crawl:** raise `concurrency` to whatever your own
origin tolerates (it is a parameter, and you are crawling yourself, so the
limit is your infrastructure and your WAF, not a third party's rate limit);
or stop crawling everything — crawl the items that changed since the last
run, plus a rotating sample. That is the change most catalogues over ~20,000
items should make on day one.
- **Validation is pure CPU** over a JSON rule set. It is not the bottleneck at
any catalogue size a Node process can hold.
- **Storage: none.** The pack persists nothing between runs, which is why there
is no database in the stack and why `verify.sh` needs no Docker.
- **One feed per target country** is an architectural boundary, not a
limitation to route around: the conditional rules and the currency check are
country-scoped. Three countries is three configs through one pipeline.
**What this comfortably covers as shipped:** a single-country catalogue in the
hundreds-to-tens-of-thousands of SKUs, with the doctor run in CI on every
deploy and on a daily cron. **What it isn't sized for out of the box:**
six-figure catalogues crawled in full every night, or multi-channel feed
transformation across Google, Meta, Amazon and TikTok — the second one is what
the feed-management SaaS category exists for, and this pack does not pretend
otherwise.
**On token savings:** we are not publishing one. Every dollar figure in this
catalogue that we stand behind comes from a harness receipt, and this pack does
not have one yet. Buy it for the bug classes above — particularly the two that
are invisible to any feed-only validator — not for a build-cost estimate we
would have to invent.
Target models
- claude-opus-5
- claude-sonnet-5
- claude-haiku-4-5
Supported stacks
- nextjs-feed
node 24.18.1 next 16.2.12 react 19.2.8 react-dom 19.2.8 typescript 6.0.3 cheerio 1.2.0 vitest 4.1.10 @types/node 24.13.3 @types/react 19.2.18 @types/react-dom 19.2.4
Estimated buyer token cost
430,000 tokens for one build pass (estimate, not a guarantee).
FAQ
What if the build fails?
`verify.sh` is the arbiter, and it is deterministic and hermetic — the product data spec is read from a file on disk, never fetched, and the storefront the consistency checker crawls is a local HTTP server the suite starts itself. No Google account, no API key, no network, no Docker. Full refund within 14 days of purchase if `verify.sh` fails on a supported configuration (the pinned stack and a model from the pack's matrix) — reply to your Stripe receipt email with the verify output attached. If your agent modified a frozen file (`test/`, `verify/`, `spec/`, `verify.sh` or the pinned configs) to get a check to pass, that falls outside the guarantee; the fix is to fix the implementation, not the checker.
Does this guarantee Google approves my products?
No, and any pack that tells you otherwise is selling you something it cannot deliver. Passing all 15 checks means two things: your feed conforms to the product data specification *as this pack transcribed it on 2026-08-02*, and it agrees with your landing pages *at the moment you ran the check*. It does not cover Google's Shopping ads policies — restricted products, misrepresentation, content and claims judged across your whole site. That review is a judgement about meaning, and no static checker can make it. The pack is built to say so out loud: `policy-violation` is marked unverifiable in the shipped rule data, the CLI prints a `NOT CHECKED` section on every run *including clean ones*, and one of the 15 acceptance checks exists purely to assert that no rule ever quietly claims to check it. A tool that reported "0 policy problems" would be more dangerous than no tool.
Google changes its spec constantly — doesn't this rot?
Your built app does not rot; it runs on pinned versions and keeps generating the same feed. What goes stale is the transcription's agreement with Google, and that is why the spec is shipped as **data** with a `retrieved` date rather than as rules buried in code. `MIGRATION.md` contains a copy-paste prompt that has your own agent read the current spec pages, diff them against the shipped file, edit only that file, and re-run the acceptance suite until green — which is the entire argument for the suite existing. Our own commitment: packs listed for sale are re-verified against current platform rules on our schedule (quarterly, plus whenever an authority announces a mandate); every re-verified version is free to prior buyers; we do not promise a delivery date, and we delist rather than sell a pack we can no longer verify. One-time purchase, free updates, no SLA.
What models does this need?
Written for `claude-opus-5`, `claude-sonnet-5` and `claude-haiku-4-5`. Because this pack is `draft`, that is the intended matrix rather than a verified one — there is no receipt yet naming the model the clean-room runs used. Tasks are pre-tagged `cheap`/`standard`/`capable` in `TASKS.md` and routed accordingly: six of the fourteen tasks are cheap-tier, seven standard, and exactly one — the final verification pass — is Opus. The PRD's estimate is **2–3 agent sessions** inside a $20/mo plan, whose binding constraint is prompt volume in Claude's 5-hour rolling window and weekly cap rather than raw tokens.
Isn't this what DataFeedWatch or Productsup already do?
For a large multi-channel retailer, yes — and you should buy the SaaS. Those platforms do feed transformation across Google, Meta, Amazon and a dozen other channels, with a UI your marketing team can use without a deploy. This pack is a different shape: it puts the checks in *your* repo and *your* CI, as code you own, for a single channel. The case it wins is the custom or headless storefront where the mismatch originates — where the feed and the page are generated by different services and drift apart between deploys. It is also $129 once rather than a subscription, which matters at small catalogue sizes and stops mattering at large ones.
I'm on Shopify — do I need this?
Probably not, and we would rather say so. Shopify's official free "Google & YouTube" channel app syncs your products to Merchant Center reading the same product data that renders your pages, which structurally avoids the biggest failure this pack protects against. Use it first. The cases where this pack still earns its price on a Shopify store: a headless front end where pages are rendered outside Shopify, prices computed by a service the channel app cannot see, or a compliance requirement to gate deploys on a feed check inside your own CI.
Can I customize the pack after the build?
Yes. Where your catalogue comes from is one class behind the `CatalogSource` interface — Shopify Admin API, your own Postgres, a nightly CSV. The spec rules are a JSON file, so tightening or relaxing a rule for your category is an edit, not a refactor. The disapproval-cause taxonomy is in that same file, so adding a cause you care about (and a rule that detects it) is additive. The one thing we ask you not to do is add a rule claiming to check policy — the acceptance suite will fail you, on purpose.
Do I own the code?
Yes. Once built it is your repo — plain TypeScript, one HTML/XML parsing dependency, and a JSON rule file, with no runtime call back to this pack or to OneShot. The only external service in the picture is Google Merchant Center itself, which you would be using anyway, and with which we have no affiliate or commercial relationship of any kind.
Prescribed services
- Railway — Railway referral credits
Disclosure: some links on this page are affiliate links. We may earn a commission if you sign up through them, at no extra cost to you. We only link to services the pack actually verified against.