OneShot

← All packs

Product Feed & Merchant Center Compliance

complex-universaldraft

A 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.

Coming soon — $129
Execution receiptVerification pending

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.

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 packFeed-management SaaS (DataFeedWatch / Productsup / Feedonomics class)Platform channel app (Shopify "Google & YouTube", BigCommerce equivalent)Hand-rolled in-houseThis pack
**Cost**"Free" (agent time only)Recurring subscription, commonly scaling with SKU count or channel countFree, if you are on that platformEngineering 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 existsFast — this is their product, and for a large catalogue on many channels they are genuinely the right answerFast, and it is maintained by the platformSlow — the failure modes are discovered from Diagnostics, not from tests2–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 belowLow on the feed itself; feed↔page consistency depends on which tier and features you buyLow for a stock storefront; it reads your platform's own product data, so the page and the feed share a sourceHigh until you have independently rediscovered the failure modes belowBounded by `verify.sh`'s 15 checks, run against a local storefront with planted drift. **No published pass rate yet**
**Lock-in**None, and no guardrailsReal — your transformation rules live in their UI, and leaving means rebuilding themReal but cheap — you are already on the platformNoneNone. 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 caseFor 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
    node24.18.1
    next16.2.12
    react19.2.8
    react-dom19.2.8
    typescript6.0.3
    cheerio1.2.0
    vitest4.1.10
    @types/node24.13.3
    @types/react19.2.18
    @types/react-dom19.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

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.