If you run an online shop and advertise on Google Shopping, Google takes your prices from a product feed: a file your shop generates every day. When the price in that file doesn't match the price on your site, Google can block your products, and customers who click an ad see a different number than they expected. So when six products looked overpriced in the feed of a home & living brand I look after, the same six in all four of its country shops, I assumed the worst.

All six were on sale. The feed seemed to show the regular price, roughly four to ten per cent higher. The shop showed the sale price.

A discrepancy that repeats identically across four independent markets is almost never a coincidence. It's a systematic cause, and I had a clean story for it: the sale had gone live in the shop and never propagated to the feed, which meant the ads had been quoting the pre-sale price for as long as the promotion had been running.

The story was wrong. There was nothing to fix. The whole discrepancy lived in my measuring instrument, and finding that out took about half a day longer than it should have.

If you ever check numbers in one tool that another tool actually uses, this lesson is for you: look at what the platform reads, not at what's easiest to look up.

Why the pattern looked so convincing

Because the stakes are real and I've been burned by this exact class of problem before. Google disapproves products when the feed price and the landing-page price diverge — its own guidance is that "prices reflected in the HTML need to match exactly the prices uploaded in Merchant Center". And a shopping ad that quotes a stale "from" price is worse than no ad: the customer arrives, sees a different number, and the only thing they learn is that you're careless.

I'd also just spent weeks on adjacent versions of this. A promotion died silently on four country shops for a month. An expired promotion didn't expire by itself. When you've seen price drift twice in the same estate, the third sighting doesn't get interrogated — it gets believed. That's the bias, stated plainly: I had a prior, and the data confirmed it, so I stopped looking.

The field that wasn't there

Here is the actual defect. I pulled prices through the Google Ads API, using the shopping_product resource. That resource has exactly one price field: price_micros, documented as "the price of the product in micros as provided by the merchant". There is no sale price on it. None. The resource exists to support bidding and performance reporting, and for those questions the base price is the only one that matters.

So I queried an endpoint that cannot express a sale, got back base prices, compared them to shop prices that included sales, and concluded the sales were missing. The absence of a sale price in my query result became, in my head, the absence of a sale price in the feed.

David McRaney has a name for this in You Are Not So Smart: the argument from ignorance, "when you decide something is true or false because you can't find evidence to the contrary."

Six SKUs. Four markets. Twenty-four data points, every one of them technically accurate, adding up to a conclusion that was entirely invented by the shape of my API call.

What the platform actually reads

The correction took five minutes once I looked in the right place. Each market's Merchant Center account pulls a primary data source configured as a File (URL) — a feed the shop itself generates, fetched once a day. I opened the data source, took the feed URL, and fetched the file.

All four live feeds carried a sale_price for exactly the six on-sale products. The effective price matched the shop for all twenty-seven products in all four markets. Merchant Center reported every attribute recognised and no issues. Google's own specification for the attribute is clear about the mechanics: sale_price tells customers what you charge during a sale, and if you don't submit an effective date range, it applies to the product immediately. The feed was correct the entire time.

Two things worth keeping from that. First, prices belong in the shop, and the feed follows on its own — editing a price directly in Merchant Center is pointless, because the next daily fetch overwrites it. Second, the only cosmetic defect in the whole exercise was a hyphen where an en dash belonged in two markets' product titles, which is a rounding error compared to the four hours I'd just spent being confidently wrong.

The rule I wrote down

To check what a platform sees, read the artefact the platform reads. Not the reporting API, however convenient it is to query — a reporting API is a projection built to answer a different question, and the fields it omits are design decisions, not facts about the world.

Concretely, for shopping feeds: go to the data source in Merchant Center, find how it's configured, fetch that exact file, and diff it against the shop's own product data. That's four more clicks than the API call and it's the difference between an audit and a guess. The same logic applies to every layer I work in — a counted conversion with a made-up value and a revenue report that collapses products into "other" are both cases of a convenient field standing in for the thing you actually care about.

And the other habit, which is the one I'd push hardest with any team: write the correction down as loudly as the finding. The original note is still in my files, with the correction sitting next to it rather than replacing it, because the gap between them is the only part a future version of me will learn anything from. Testing whether a dip is a signal before you go hunting for a bug is the same discipline pointed at a different symptom: prove the anomaly exists before you explain it.

I didn't find six mispriced products. I found one mis-specified query, and the four markets were just my mistake, copied four times.

Sources & further reading

External
Google Ads API — ShoppingProduct resource reference
Google Merchant Center — sale price [sale_price] attribute specification
Google Merchant Center — How to fix: mismatched product price

Related posts
Price governance in ecommerce: how a promotion died silently on four country shops for a month
An expired promotion doesn't expire by itself
A counted conversion with a made-up value is worse than no tracking
"Other products" is a measurement defect, not a category
How to test whether a dip is a signal before you go hunting for a bug