How to Monitor Shopping Prices on Google + Yahoo in 2026
Price monitoring lives or dies on coverage. A retailer whose own feed says "$89.99" is only half the story — the other half is what the market actually shows shoppers, and that varies by engine. Google and Yahoo Shopping surface different merchants, different prices, and different availability for the same query. A monitoring loop that reads only one engine sees a slice of the market.
This playbook builds a two-engine price monitor on top of a single endpoint — /api/shopping — that returns Google Shopping with engine=google and Yahoo Shopping with engine=yahoo. You query both, normalize the price strings, store a daily baseline, and alert when the lowest offer drops. I ran this pattern against live queries in August 2026, and the honest limits — null prices, a ~10–11 listing depth cap — are built into the playbook below, not papered over.
TL;DR: Hit /api/shopping?engine=google and /api/shopping?engine=yahoo for the same product, merge the results.shopping arrays, normalize each price string to cents, and compare against yesterday's stored minimum. When the current lowest offer is lower, you have a price drop. Prices are returned where the placement renders them — some placements omit a price, so price can be null; skip those rather than treating them as $0.
Why two engines, not one
Google Shopping and Yahoo Shopping are separate product surfaces with their own merchant sets and orderings. The same query in both returns a different offer set — a merchant may surface on Yahoo and not Google, or price the same product differently in each. Cross-engine monitoring does two things: it widens coverage (you see offers either engine alone would miss) and it gives you a second opinion on any single price change (a drop visible in both is more trustworthy than one visible in a single listing).
The two engines also use different field names. Google returns link/source/product_rating/product_reviews; Yahoo returns url/merchant/rating/reviews. The shared fields (position, title, price, thumbnail) line up, which is all a price monitor needs.
The two calls: Google and Yahoo through /api/shopping
Both engines live on the same endpoint. The only thing that changes is the engine parameter:
| Request | Returns |
|---|---|
/api/shopping?q=sony+wh-1000xm5&engine=google&num=20 | Google Shopping product listings |
/api/shopping?q=sony+wh-1000xm5&engine=yahoo&num=20 | Yahoo Shopping product listings (also the default) |
Each product result carries position, title, price, currency, url, thumbnail, and a merchant field. Yahoo also includes a ready numeric extractedPrice, so you can skip a string-parsing step on that engine.
What to expect before you build: the honest data
Two limits decide whether this pattern works for you, and both are worth stating before the code.
- Prices can be null. In my August 3, 2026 runs, prices came back
nullon 0, 0, and 1 of the placements across three query sets. A re-test the next day returned prices on 6–8 of 10. A monitoring loop must treat a missing price as "no data this poll," never as $0. - Depth caps at ~10–11 listings. I requested
num=100and got the same 10–11 back. There is no pagination, so to cover a broad catalog you split it across many queries rather than paging one query deeper.
The related Google product-SERP field audit shows the same pattern on the web-SERP surface: organic results and People Also Ask are dependable, but normalized Shopping items are not guaranteed on any given query.
Query both engines in Node.js
Here is a small function that queries either engine and returns the product list, then uses it to pull both sides of the market:
async function shopping(query, engine) {
const res = await fetch(
`https://apiserpent.com/api/shopping?q=${encodeURIComponent(query)}&engine=${engine}&num=20`,
{ headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const json = await res.json();
return json.results.shopping ?? [];
}
const google = await shopping('sony wh-1000xm5', 'google');
const yahoo = await shopping('sony wh-1000xm5', 'yahoo');
const all = [...google, ...yahoo];
Two HTTP requests, one merged list of offers. That merged list is your raw material — now turn the price strings into numbers you can compare.
Normalizing prices (and handling null)
Prices arrive as display strings like "$399.99". To compare them, strip currency symbols and convert to an integer number of cents. The critical detail: some placements do not render a price at all, so price can be null. Treat null as "no price available," not as $0 — a $0 reading would instantly and wrongly register as a price drop.
function toCents(price) {
if (!price) return null; // honest: some placements have no price
const m = String(price).replace(/[$,]/g, '').match(/[\d.]+/);
return m ? Math.round(parseFloat(m[0]) * 100) : null;
}
// Lowest priced offer across both engines, skipping nulls:
const best = all
.filter(p => toCents(p.price) !== null)
.sort((a, b) => toCents(a.price) - toCents(b.price))[0];
console.log('Lowest offer:', best.title, best.price, best.merchant || best.source);
Filtering nulls first means your "lowest price" is computed only over placements that actually showed a price — which is the honest answer, not a guess.
The price-drop loop
A one-off comparison is a snapshot. A monitor stores a baseline — the lowest price per product per day — and compares each new reading against it. When the current minimum falls below the stored baseline, fire an alert:
// lastSeen: { [title]: lowest cents observed yesterday }
const today = await shopping('sony wh-1000xm5', 'yahoo');
for (const p of today) {
const cents = toCents(p.price);
if (cents === null) continue; // no price on this placement
if (lastSeen[p.title] !== undefined && cents < lastSeen[p.title]) {
console.log('PRICE DROP:', p.title, '→', p.price, 'at', p.merchant);
}
lastSeen[p.title] = Math.min(lastSeen[p.title] ?? cents, cents);
}
// persist lastSeen to a store; it becomes tomorrow's baseline
The loop is intentionally small: query, normalize, compare, store. Run it on a schedule — daily is enough for most product categories — and you get a price history plus a drop alert for every tracked product. For a deeper walkthrough of the alerting half, see our price drop alerts post. If you are comparing at SKU level rather than title level, the confidence-bucketed matching in Google Shopping SKU matching is the production-grade version of the merge step.
Scheduling and honest cost
Shopping search costs $0.60 per 1,000 requests on the Default tier, $0.54 per 1,000 on Growth, and $0.42 per 1,000 on Scale, for both Google and Yahoo engines. Shopping is free-eligible from the 10 shared free calls, then bills per call — credits never expire and there is no subscription. Concretely: monitoring one product across both engines once a day is two calls — 60 products a day is 120 calls, which at Scale pricing is about 5 cents. The bill tracks the number of queries you run, not the number of products you track.
Two practical notes. First, request num=20 or higher so your baseline covers more than the top few placements — though remember the source returns ~10–11 regardless. Second, store the raw price string alongside the numeric value, so when a price changes you can see exactly what the market showed rather than only the delta. The Shopping API hub and the Google Shopping and Yahoo Shopping references document every field.
Monitor both engines. Catch every drop.
Query Google and Yahoo Shopping through one endpoint — /api/shopping — and merge the offers. Flat per-call pricing from $0.42/1K at Scale, credits never expire, no subscription. Try it with the free API key.
Get Your Free API KeyExplore: Google Shopping API · Yahoo Shopping API · Shopping API · Docs
FAQ
Why monitor both Google and Yahoo Shopping?
Google and Yahoo Shopping surface different merchant sets and orderings for the same query, so the same product can appear at different prices. Querying both gives a broader view of the market and lets you cross-check a price change instead of trusting a single source.
Is a price always returned for every product?
No. In my August 2026 tests prices were null on most placements in a first run (0/10, 0/10, then 1/11) and 6–8 of 10 on re-test. Some placements render without a visible price, so the price field can be null. A monitoring loop must skip nulls rather than treating them as a real price of zero.
How do I detect a price drop?
Normalize each price string to a numeric value, store the lowest offer per product per day, and compare each new reading against the previous baseline. When the current minimum is lower than the stored baseline, you have a price-drop signal to alert on.
How many listings do I get per product query?
About 10–11 listings per query, no matter the num you pass. There is no pagination on the shopping rail, so a broad catalog must be split across many queries rather than paged.
What does shopping price monitoring cost?
Shopping search costs $0.60 per 1,000 requests on the Default tier, $0.54 per 1,000 on Growth, and $0.42 per 1,000 on Scale for both Google and Yahoo engines. Shopping is free-eligible from the shared 10-call pool. Credits never expire and there is no subscription, so cost scales with how many product queries you run.



