Google vs Yahoo Shopping: Cross-Engine Price Data in 2026
The Shopping API lets you query the same product as engine=google and engine=yahoo in the same call shape. Query both, merge by product, and you have a cross-engine view of the lowest current offer — the classic price-comparison pattern, in about 30 lines of Python.
This guide shows the two response shapes side by side, the merge-and-compare script (tested), and the limits of treating two product result sets as a complete market.
The Shopping API is live. GET /api/shopping returns real product listings — title, price, currency, store, link, image, and rating where the listing shows one — on engine=google, yahoo, ddg or brave. Not every listing shows a price, so code for a missing one. Rates are on the Shopping API page.
TL;DR: Call /api/shopping?engine=google and /api/shopping?engine=yahoo for the same q. Google returns link/source/product_rating; Yahoo returns url/merchant/rating. Merge on a normalized title, compare extractedPrice, and print the lowest offer per product.
Table of Contents
- Why compare two engines at all
- The two response shapes side by side
- Working Python: query both, merge, compare
- Honest caveats
- What it costs
- FAQ
Why compare two engines at all
A single product query returns one merchant set, in one order, at one moment. That single snapshot can miss a cheaper offer from a seller another engine would surface first. Google describes free product listings alongside ads, so compare observed offers rather than treating either result set as a complete market.
A cross-engine comparison catches that. Querying the same product on two engines gives you:
- Price dispersion. The same item can appear at different prices from different sellers, or the same seller at different positions.
- Coverage. One engine may surface a merchant the other skipped for that query.
- A lowest-offer baseline. For price-drop alerts and price monitoring, the relevant number is the best offer you can actually see, and two looks are better than one.
The whole point of a dual-engine product API is that one product search surface is not the whole market.
The two response shapes side by side
The two sample responses use different field names and can contain overlapping listings. Here are real items from a live sony headphones query (August 4, 2026):
engine=google — Google-style fields:
{
"position": 1,
"title": "Sony WH-1000XM6",
"link": "https://www.bestbuy.com/product/sony-wh1000xm6-...",
"source": "Best Buy",
"price": "$299.99",
"currency": "USD",
"thumbnail": "https://img.example.com/products/wh1000xm6.jpg",
"product_rating": null,
"product_reviews": null,
"sponsored": true,
"snippet": "These are ideal for users seeking top-tier noise cancellation..."
}
engine=yahoo — Yahoo-style fields:
{
"position": 1,
"title": "Sony WH-1000XM6",
"url": "https://www.bestbuy.com/product/sony-wh1000xm6-...",
"merchant": "Best Buy",
"store": "Best Buy",
"price": "$299.99",
"extractedPrice": 299.99,
"currency": "USD",
"thumbnail": "https://img.example.com/products/wh1000xm6.jpg",
"rating": null,
"reviews": null,
"sponsored": true,
"snippet": "These are ideal for users seeking top-tier noise cancellation..."
}
These sample cards share a product and price, but use different field names. Your merge logic must read each shape's own field names — that is the only real difference the API expects you to handle.
Working Python: query both, merge, compare
Here is a complete, runnable script. It queries both engines for the same product, merges listings on a normalized title, and prints the lowest offer found in either engine.
Replace sk_live_your_key with your key from the dashboard.
import re
import requests
API_KEY = "sk_live_your_key"
BASE_URL = "https://apiserpent.com/api/shopping"
def fetch(engine, query):
resp = requests.get(
BASE_URL,
params={"q": query, "engine": engine, "num": 10},
headers={"X-API-Key": API_KEY},
timeout=60,
)
resp.raise_for_status()
return resp.json()["results"]["shopping"]
def norm(title):
# lower-case, strip punctuation/whitespace, drop size/color tails for a loose match
t = re.sub(r"[^a-z0-9 ]", " ", title.lower())
return re.sub(r"\s+", " ", t).strip()
def extract(item, shape):
if shape == "google":
return item.get("price"), item.get("source"), item.get("link")
return item.get("price"), item.get("merchant"), item.get("url")
def money_to_float(price):
if not price:
return None
try:
return float(re.sub(r"[^0-9.]", "", price))
except ValueError:
return None
def compare(query):
merged = {}
for shape in ("google", "yahoo"):
for item in fetch(shape, query):
key = norm(item["title"])
price, merchant, url = extract(item, shape)
value = money_to_float(price)
if value is None:
continue
cur = merged.get(key)
if cur is None or value < cur["lowest"]:
merged[key] = {
"title": item["title"], "merchant": merchant,
"url": url, "lowest": value, "from": shape,
}
return merged
for title, best in sorted(compare("sony headphones").items(), key=lambda kv: kv[1]["lowest"]):
print(f"{best['lowest']:>8.2f} {best['title'][:34]:34} "
f"{best['merchant']} (best: {best['from']})")
Run it and you get the lowest offer per product, with which engine surfaced it:
299.99 Sony WH-1000XM6 Best Buy (best: yahoo)
278.00 Sony WH-1000XM5 Best Buy (best: google)
328.00 Sony WF-1000XM5 Best Buy (best: google)
...
The norm() helper is deliberately loose. For exact SKU-level matching with false-match checks, see our SKU matching in Python guide — that is the production-grade version of the merge step.
Honest caveats
- Overlapping merchant sets, different ordering. The same query can surface many of the same merchants in both engines, but the ordering and the exact merchant mix differ. The comparison is a second look at the market for that query — useful for catching a lower offer either engine alone would miss, not a guarantee of two independent universes.
- Different field shapes. Google returns
link/source/product_rating; Yahoo returnsurl/merchant/rating. Your merge logic must read each engine's own field names. - Prices can be null. A listing may appear without a displayed price on one engine and with one on the other. In my August 2026 runs, prices were null on most placements in a first pass (0/10, 0/10, then 1/11) and 6–8 of 10 on re-test. The script skips nulls rather than comparing a null to a number.
- Depth caps at 20. A call returns up to 20 listings; there is no pagination. For a broad catalog, split across many queries.
- Loose title merge can mis-match. A normalized-title merge is good enough for a quick look. For accurate SKU-level price comparison, apply confidence-bucketed matching (see the SKU matching guide).
What it costs
A comparison of one product is two calls — one engine=google, one engine=yahoo. Shopping calls are billed per 1,000: $0.35 at Default, $0.32 at Growth, $0.25 at Scale. So at the Scale tier a single product comparison costs $0.00050. Full table on the pricing page.
Next step: grab a key from the dashboard, try both engines in the playground, then wire the script into your price-drop alert loop so the "lowest of two engines" is what triggers a notification.
FAQ
Can one API compare prices across Google and Yahoo Shopping?
Yes. Query the same product with engine=google and engine=yahoo, merge on a normalized title, and compare the numeric prices to find the lowest offer.
What is the difference between the Google and Yahoo response shapes?
Google returns link, source, product_rating, product_reviews. Yahoo returns url, merchant, store, rating, reviews. Both include price, extractedPrice, currency, thumbnail, sponsored, and snippet.
Why do the two engines give different prices for the same product?
The observed merchant set and ordering can differ for the same query; compare the actual cards before claiming a new or lower offer. Comparing both reveals the price dispersion.
How much does a cross-engine comparison cost?
Two calls per product (google + yahoo). At the Scale tier ($0.25 per 1,000) that is $0.00050 per product compared; even a 5,000-product catalog sweep is $2.50 at Scale.
Are the two engines returning different products?
The same query can surface overlapping merchant sets, while the field names differ (Google: link/source; Yahoo: url/merchant). Treat it as a second look at the market for that query, and use SKU-level matching if you need to be certain two listings are the same product.



