Google Shopping Scraper — Offers, Price History & Deals avatar

Google Shopping Scraper — Offers, Price History & Deals

Pricing

from $2.00 / 1,000 products

Go to Apify Store
Google Shopping Scraper — Offers, Price History & Deals

Google Shopping Scraper — Offers, Price History & Deals

Google Shopping products by keyword or product ID: price, store, rating, and per product the store offers Google shows (direct links, stock, delivery, returns) with each store's daily price history (up to 12 months in the US, DE, FR) and Google's typical price range.

Pricing

from $2.00 / 1,000 products

Rating

0.0

(0)

Developer

Berkan Kaplan

Berkan Kaplan

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

Get the products Google Shopping shows for any search, in 26 countries (15 of them tested on the Apify platform): price, store, rating, review count, discount badges — and, for each product, what Google's own product page shows: the store offers Google lists (typically 3–5) with store links, price, stock, delivery cost and returns, each store's daily price history for up to about 12 months, and Google's typical price range. One row per product, in one run.

Already know the products? Give their Google product IDs (from an earlier run) and re-check offers and prices on a schedule.

No Google account, no API key, no browser. Requests go through Apify's Google SERP proxy.

Quick start (API)

curl -X POST "https://api.apify.com/v2/acts/foxlabs~google-shopping-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"queries": ["sony wh-1000xm5"], "country": "us", "maxProductsPerQuery": 5}'

What you get

GroupFields
Product (search result)position, title, productId (Google's product ID — use it to re-check the product later), catalogId, price, priceText, currency, oldPrice, priceNote (Google's note next to the price: "Usually $225", or the store's own-currency price such as "(€278)" when Google converted it), unitPriceText, merchant, moreOffers (Google shows "& more" stores), condition ("Refurbished"), deliveryText, returnsText, rating, reviewsCount, reviewsCountText ("17K"), badge ("25% OFF", "LOW PRICE"), imageUrl
Store offersoffersCount, offers[] — per store: merchant, merchantDomain, url (the seller's link, Google's tracking parameters removed), price, oldPrice, discountText, deliveryText, deliveryCost, totalPrice (price + delivery when the delivery label gives the cost), returnsText, stockText, inStock, condition (used, refurbished, pre-owned…), promotionText ("Save $15.00"), merchantRating, offerTitle, label ("Best price", "Most popular"), offerId · offersText (one-line summary)
Deal signalslowestPrice, lowestPriceMerchant, lowestPriceUrl, lowestPriceCondition, highestPrice, typicalPriceLow, typicalPriceHigh, typicalPriceText (Google's "Typically $199 to $300"), priceVsTypical (below / within / above), historyLowestPrice, historyLowestPriceDate and historyLowestPriceMerchant (the most recent day a listed store had that price), historyHighestPrice, historyFrom, historyTo, isAtHistoryLow, pctAboveHistoryLow
Price historypriceHistory[] — per store: merchant, firstDate, lastDate, days, minPrice, maxPrice, lastPrice, and changes[] (the first day, each day the price changed, and the last day) or points[] (every day) · priceHistoryStatus, priceHistoryNote (why there is none, in plain words)
Product detailsspecs (Google's specification table), description, variants (colours/sizes Google lists)
ContextgoogleShoppingUrl, detailsStatus, detailsNote, query, searchVariant (which Google listing found the product), inputType (search / productId), inputProductId, country, language, scrapedAt, error (the reason on status rows, null on product rows)

Deal signals compare like with like. Offers Google labels used, refurbished or pre-owned are left out of lowestPrice and of the history summary, so a refurbished $249.99 offer is not compared with the new-product price history. Promotions Google shows in the same place ("Save $15.00") go to promotionText and do not leave an offer out. If every offer carries a condition label, all are used and lowestPriceCondition names the condition. pctAboveHistoryLow compares lowestPrice with historyLowestPrice (rounded to 0.1%); it is below 0 when today's price is lower than any price in the history, which in platform runs happened only when the cheapest store had no history series.

Sample output

A real row from an Apify platform run on 2026-09-30 (run HWXUreNVwIQOtIbB7, build 0.1.5: sony wh-1000xm5, United States), trimmed: 2 of 3 offers, 1 of 3 store price histories (3 of its 6 changes entries) and 4 of 13 specification lines shown.

{
"position": 1,
"title": "Sony WH-1000XM5 Noise Canceling Wireless Headphones",
"productId": "11726664398501807381",
"price": 298,
"priceText": "$298.00",
"currency": "USD",
"oldPrice": 398,
"merchant": "Best Buy",
"moreOffers": true,
"condition": null,
"deliveryText": "Free delivery",
"rating": 4.6,
"reviewsCount": 17000,
"reviewsCountText": "17K",
"badge": "25% OFF",
"detailsStatus": "ok",
"offersCount": 3,
"offersText": "Best Buy $298.00 · Sony $299.99 · Office Depot $398.09",
"offers": [
{ "merchant": "Best Buy", "merchantDomain": "bestbuy.com", "url": "https://www.bestbuy.com/product/sony-wh-1000xm5-wireless-noise-cancelling-over-the-ear-headphones-black/J7XSRH5CXG/sku/12903258?ref=212&loc=marketplace", "price": 298, "priceText": "$298.00", "oldPrice": 398, "discountText": "25% off", "deliveryText": "Free delivery", "deliveryCost": 0, "totalPrice": 298, "stockText": "In stock online", "inStock": true, "condition": null, "offerTitle": "Sony - WH-1000XM5 Wireless Noise Cancelling Over-the-Ear Headphones - Black", "label": "Best price" },
{ "merchant": "Sony", "merchantDomain": "electronics.sony.com", "url": "https://electronics.sony.com/audio/headphones/headband/p/wh1000xm5-b", "price": 299.99, "priceText": "$299.99", "oldPrice": 400, "discountText": "25% off", "deliveryText": "Free delivery between Fri - Mon", "deliveryCost": 0, "totalPrice": 299.99, "returnsText": "Free 30-day returns", "stockText": "In stock online", "inStock": true, "condition": null, "merchantRating": 4.8 }
],
"lowestPrice": 298,
"lowestPriceMerchant": "Best Buy",
"lowestPriceCondition": null,
"highestPrice": 398.09,
"typicalPriceLow": 199,
"typicalPriceHigh": 300,
"typicalPriceText": "Typically $199 to $300",
"priceVsTypical": "within",
"priceHistoryStatus": "available",
"historyFrom": "2025-09-29",
"historyTo": "2026-09-30",
"historyLowestPrice": 198,
"historyLowestPriceDate": "2026-09-02",
"historyLowestPriceMerchant": "Best Buy",
"historyHighestPrice": 399.99,
"isAtHistoryLow": false,
"pctAboveHistoryLow": 50.5,
"priceHistory": [
{ "merchant": "Best Buy", "firstDate": "2026-08-12", "lastDate": "2026-09-30", "days": 50, "minPrice": 198, "maxPrice": 398, "lastPrice": 298,
"changes": [{ "date": "2026-08-12", "price": 248 }, { "date": "2026-08-31", "price": 398 }, { "date": "2026-09-02", "price": 198 }] }
],
"specs": { "Brand": "Sony", "Noise Canceling": "Yes", "With Microphone": "Yes", "Color": "Midnight Blue, Smoky Pink" },
"variants": ["Black", "Silver", "Smoky Pink", "Blue"],
"query": "sony wh-1000xm5",
"searchVariant": "relevance",
"country": "us"
}

How it works

  • Search results. A Google Shopping results page shows about 40–50 different products (40–49 on 12 saved pages; 47 in platform run RKYa2UHA1hOlthVFV). Google has no second results page on the addresses the SERP proxy serves (start=40 and the infinite-scroll request both returned 0 products in tests), so for more products the Actor also reads the sort orders and price bands Google prints on the first page — the same search sorted by price or rating, or limited to "Under $35", "$35–$70"… — and removes duplicates. On the Apify platform, wireless earbuds (US) gave 199 different products from 8 Google pages (run fpHQhLcCmOyEEZ5qB), and 6 broad US searches, run 11 times in 2 runs, returned the 200 products asked for 10 times (4k tv returned 123 once and 200 in the other run; runs 3dNEzA23rN88qH8cg, ofIVrQSh7rVpXCmOr). It does not promise "every product for a search".
  • Store offers and price history. For each product that has a Google product page (catalog products; 88% of 2,777 search rows in platform runs — the others are single-store listings), the Actor opens that page: one extra Google request per product. It lists the stores Google shows in "Buying options" (3–5 on 181 of 185 product pages in platform runs, median 3) and, where Google shows it, each store's daily price history (up to 367 days). Google loads more stores ("More stores") with a script; the Actor does not load them, so offers beyond those are not included.
  • Pages that Google marks as another country's are retried and never delivered. Google sometimes answers as if the request came from another country (on the Apify platform, 6 of 351 Google requests in 54 runs, 1.7%; in local tests, pages came back Spanish, Brazilian or Indian, with EUR, BRL or INR prices). The Actor checks every page's currency and, when Google states it, the page's region, and asks again up to 3 times; a page that is still from the wrong country is dropped and counted in SOURCE_REPORT (marketCheck). In the platform runs all 6 were retried and none was delivered. A neighbouring country with the same currency and language (for example Austria for Germany) cannot be told apart this way.
  • Only delivered products are charged. A search with no result, a product ID that cannot be opened and a product ID that cannot be read each leave one free row with an error explaining why. SOURCE_REPORT in the key-value store lists, per search, the Google pages used, duplicates, price-filtered products and details that failed.

Price history by country

Measured in September 2026 on product pages where history was requested: Apify platform runs of builds 0.1.1–0.1.6 (57 runs), plus pages saved during development.

CountryProduct pages with price history (different products)Platform runs
United States93 of 94 (41), plus 14 of 15 saved pages17 runs, including Ddsy80BUMi1fwxItP, AWDXSo5gxBZxBtNJF, tvfQhGmVtX5F3HwKu
Germany40 of 41 (23), plus 6 of 6 saved pagesKfGZFyVcacK7wREZT, 5cz3iiIrzJEcxUQHv, 6cJ72ffLjGdOtrxMu, zQMYsJ9FeCkXomTbw
France3 of 3, plus 2 of 2 saved pages5YzCZcL4onfYOYZOW
Spain5 of 5 (4)t5zwzNnExuLg6eGei, o9TaSVqzEOatahQrN
Canada · Australia · Netherlands3 of 3 eachdmCCFTkoUd52j2XOc · e7IqE3FriF3azFdgc · zMz1LusbZQ9pCzdlH
India · Japan2 of 2 each38vsq7ZPes47YquMZ · z4SPhE47eM5kDbb6e
Poland5 of 6 (5)inBgJy8dcRZZVRsv8, dQ2VVjlHaUZVzofW6
Italy · Sweden1 of 3 · 1 of 2pHp19Yv7bE3jYxGJR · T7aRDWbEk4yoowSbB
United Kingdom0 of 4, plus 0 of 5 saved pagesX3thTxtQjZUVRC0Pr, tIQltRmLF8OX8ne71
Turkey0 of 3, plus 0 of 3 saved pagesjhd5PPQM25PKDY9bb
Brazil0 of 83KEB2AdkbRjKGrXtj, bwJ5utuIH5IIoo7cS

The small samples show whether Google offers price history in a country, not an exact rate. In the United Kingdom, Turkey and Brazil, priceHistoryStatus is not-available-in-country and priceHistoryNote says so. Ireland, New Zealand, Austria, Switzerland, Belgium, Portugal, Czechia, Norway, Denmark, Finland and Mexico were not tested; a product without history there says that coverage has not been measured yet.

Input & filters

InputWhat it doesDefault
queriesProduct searches, one per line ("sony wh-1000xm5", "espresso machine")—
productIdsRe-check known products: the productId from an earlier run, or a Google Shopping product link containing prds=…gpcid:…. Each returns the product with its offers and price history—
countryWhich Google Shopping: stores, prices and currency (26 countries; 15 tested)us
languageInterface language; empty = the country's main language—
maxProductsPerQueryProducts per search, 1–300 (tested up to 200: how many more you get depends on the sort orders and price bands Google prints for the search). The Console form starts at 320
includeDetailsStore offers, price history, typical range, specs (one extra Google request per product)on
priceHistorychanges (the first day, each day the price changed, and the last day), daily (every day), nonechanges
sortByrelevance, price_low_to_high, price_high_to_low, rating — Google's own sort (one extra Google request per search). Google's price order does not always follow the listed pricerelevance
minPrice / maxPriceKeep products whose search-result price is in this range (the country's currency)—
maxSearchPagesPerQueryUpper bound on Google result pages for one search (the sort orders and price bands Google prints usually give 5–8)8

Values the input form checks (country, sort, number ranges) are rejected before the run starts, also when sent through the API. Others (no search and no product ID, a malformed language code, minPrice above maxPrice) stop the run with the reason in its status message. A product ID that cannot be read becomes a free status row, so the other IDs still run.

Example inputs (copy & paste)

Price check for one product, United States:

{ "queries": ["sony wh-1000xm5"], "country": "us", "maxProductsPerQuery": 10 }

Coffee machines in Germany, in Google's "Price: low to high" order (it does not always follow the listed price):

{ "queries": ["kaffeevollautomat"], "country": "de", "sortBy": "price_low_to_high", "maxProductsPerQuery": 20 }

Category scan without store offers (faster: the first request gives about 40–50 products, each further page about 30 new ones):

{ "queries": ["wireless earbuds"], "includeDetails": false, "maxProductsPerQuery": 150 }

Daily re-check of known products (use a schedule):

{ "productIds": ["11726664398501807381"], "country": "us", "priceHistory": "none" }

Use cases

  • Competitor price monitoring: which stores sell a product, at what price and delivery cost, and how each store's price moved over the last year.
  • Deal verification: is today's price really low? Compare lowestPrice with historyLowestPrice and Google's typical range.
  • Category research: products, prices, ratings and review counts for a category, sorted or price-banded.
  • Affiliate and deal sites: current offers with store links and discount badges.
  • Scheduled monitoring: re-check a list of productIds daily or weekly.

Performance

Apify platform runs of builds 0.1.1–0.1.6 (1024 MB unless noted):

InputProducts (with store offers)Google requestsRun timeRun
sony wh-1000xm5, US, 3 products (the form's starting input)3 (3)4–516–90 s (7 runs)fastest yFsNWp0wddVSZF0yb, slowest axv6WTyFBdWr3S4q0
the same at 256 MB3 (3)469 sN8ds2skEdXmUdWKv3
sony wh-1000xm5, US, 10 products10 (8)9 · 1081 s · 41 sDdsy80BUMi1fwxItP · GuRe6euV8GJSLU9sw
the same at 256 MB10 (9)13199 sOK1okLY6oO4hBRHHr
kaffeevollautomat, Germany, 20 products20 (19)21188 sKfGZFyVcacK7wREZT
robot vacuum, US, 30 products30 (29)35397 stvfQhGmVtX5F3HwKu
5 product IDs, US5 (5)622 sAWDXSo5gxBZxBtNJF
wireless earbuds, US, 200 products, no details199 (0)8176 sfpHQhLcCmOyEEZ5qB
6 searches × 200 products, US, no details, 256 MB1,200 (0)38895 sofIVrQSh7rVpXCmOr

Run time depends mostly on Google's response time through the proxy: the same 3-product input took 16–90 s. Across 54 platform runs, the median request took 2.4–36 s depending on the run (8 s in a typical run), and the slowest 10% took up to 77 s. A request that gets no data for 90 s, or a 429 or 5xx answer, is sent again after 2 s; if that fails too, the page is requested once more the same way (at most 4 sends, about 6 minutes for one page). 5 of 351 requests were re-sent. Product pages are read 6 at a time. Memory peaked at 64–178 MiB; the three runs at 256 MB (OK1okLY6oO4hBRHHr, ofIVrQSh7rVpXCmOr, N8ds2skEdXmUdWKv3) finished normally.

Data quality

Measured on the Apify platform in 57 runs of builds 0.1.1–0.1.6:

  • Store offers (builds 0.1.5–0.1.6, 13 runs: 226 offers on 66 product pages in the US, Germany, the UK, Poland and Spain): store, price, stock and offer title on 100%; store link on 98.7% (3 offers on one page came without a link; since 0.1.6 such a page is read once more); delivery on 98%; returns on 70%.
  • Price history matches the offers: in the same runs, 204 of 204 store histories belong to a listed store and end at that store's current offer price (all builds: 529 of 537; the 8 others were Polish offers without a price before 0.1.4).
  • Search results (2,777 rows in 47 runs, 15 countries): title, price and store on 100%; rating and review count on 84%; Google product ID on 88% (the rest are single-store listings); old price 31%; badge 36%. No product appeared twice in a run (51 of 51 runs with products, including 1,200 of 1,200 in ofIVrQSh7rVpXCmOr).
  • Price history can be missing on a single answer: of the 143 product pages that are read again when the block is missing, 14 came without it on the first read and 12 had it on the second. In the 12 countries where we saw Google show price history (US, Canada, Australia, Germany, France, Spain, the Netherlands, India, Japan, Poland, Italy, Sweden), such a page is read once more; SOURCE_REPORT counts these (marketCheck.historyRetries, historyRecovered).
  • Numbers are read in the country's format ("235,00 €", "₺13.999,30", "$1,299.00"); abbreviated review counts are expanded ("17K" → 17000, "2,2 B" in Turkish → 2200, "2,6 tn" in Swedish → 2600) and the original text is kept next to them. A value Google does not show is null, never 0.
  • Images: search rows often have no imageUrl (39% have one) because Google inlines the first thumbnails; rows with store offers take the image from the product page (185 of 185).
  • Rating and review count come from the search result, so rows opened by product ID have none.

Pricing

Pay per event:

  • product — every product row delivered;
  • product-details — added when the row carries at least one store offer (the product page was read).

Apify may also charge its Actor start event; the Pricing tab lists every event and its price. Status rows (no results, a product ID that cannot be opened or read, a wrong-country page) are free. With includeDetails: false each row is charged only product.

Integrations

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('foxlabs/google-shopping-scraper').call({ queries: ['sony wh-1000xm5'], maxProductsPerQuery: 5 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Python (the same calls; not run as code yet — the same input ran on the platform as run VtqINt0jDlShJ9pLp):

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("foxlabs/google-shopping-scraper").call(run_input={"queries": ["sony wh-1000xm5"], "maxProductsPerQuery": 5})
items = client.dataset(run["defaultDatasetId"]).list_items().items

Make, Zapier and n8n: use Apify's "Run Actor" and "Get dataset items" steps (not tested with this Actor yet).

FAQ

Why only 3–5 stores per product? Those are the stores Google itself lists on the product page. Google loads more ("More stores") with a script; the Actor does not load them.

Can I search by EAN / GTIN / UPC? Not reliably. In our tests a barcode typed into Google Shopping returned mostly unrelated products (for a verified Nintendo Switch OLED UPC, the first result was a pair of socks and a Switch OLED in another colour was 3rd). Search by product name, or use the productId of a product you found.

How do I monitor prices every day? Run a search once, keep the productIds you care about, and schedule a run with productIds. Each row has the current offers, and where Google shows it (not in the UK, Turkey or Brazil), priceHistory has Google's own history, so you do not need to wait months to see a trend.

Why is priceHistory empty? Google does not show price history for every product, and not in every country (none in the UK, Turkey and Brazil in our tests). priceHistoryNote says which case it is.

What is productId? Google's product group ID (the gpcid in Google Shopping links). In our tests the same ID reopened the product hours later; how long an ID stays valid over weeks has not been measured yet. Single-store listings have none.

Is lowestPrice the cheapest offer? It is the cheapest offer without a used, refurbished or pre-owned label, among the stores Google lists (a promotion does not leave an offer out). The full list, with conditions and promotions, is in offers.

Are store links direct? Mostly. offers[].url is the seller's link from Google's page (98% of offers have one; a few sellers are price-comparison sites). Google's srsltid, utm_* and gclid are removed; other parameters, including some sellers' campaign tags, are kept because stores may need them.

Why fewer products than I asked for? The Actor reads page 1 plus the sort orders and price bands Google prints on it — at most maxSearchPagesPerQuery pages (default 8) — and stops early when 2 pages in a row bring nothing new. Narrow searches end early; broad ones can end a little short too (wireless earbuds: 199 of 200). SOURCE_REPORT shows the pages used.

Why do I get products that do not match my search? For a search Google cannot match, Google Shopping shows other products instead of an empty page: a nonsense test search returned jeans, shoes and a ring (run n8NgBFYiIBc8u0l0i). The Actor delivers what Google shows, so check that the titles fit your search.

Troubleshooting

  • "Google Shopping shows no products for …": try a broader or differently worded search, or check the country.
  • "Google answered as another country": Google kept answering from another country after 3 tries; nothing was delivered for that search. Run it again.
  • "Apify Google SERP proxy is not available to this run": please open an issue on the Issues tab with the run ID.
  • "… is not a Google product ID": use the productId value (digits) from an earlier run or a Google Shopping link that contains prds=…gpcid:…. Old /shopping/product/… links no longer work on Google.
  • Data is what Google Shopping publicly shows at run time; prices change often.
  • The price is the one Google shows on the search result; for a few listings it is a rental or subscription price (seen once in our runs: a rent-to-own listing at $22.99 for headphones).
  • Google may change its pages without notice; fields can then come back empty until the Actor is updated. Please open an issue with the run ID.
  • Sponsored and organic results are not told apart: the pages the Actor reads carry no "Sponsored" label (0 on 25 saved result pages).
  • Google, Google Shopping and the store names are trademarks of their owners; this Actor is not affiliated with them.

Support

Open an issue on the Issues tab with the run ID and the input, or write to info@foxlabs.com.tr.

Changelog

Dates are UTC.

0.1.7 — 2026-09-30

  • Promotions Google puts where it shows an offer's condition ("Save $15.00", "5% off Summer sale") now go to the new offers[].promotionText and no longer count as a condition. Before, such offers were left out of the deal signals: in 4 of 185 platform rows lowestPrice skipped a cheaper new offer.
  • A foreign store's price in its own currency ("(₹98,990)" under a dollar price) now goes to priceNote. Before, it was read as oldPrice (22 US search rows).
  • Free delivery written in Polish, Swedish or Japanese gives deliveryCost 0; Swedish review counts ("2,6 tn") are expanded.
  • An offer Google lists twice (same store, price and link) is kept once.
  • historyLowestPriceDate and historyLowestPriceMerchant name the most recent day a store had the lowest price (before: the first store in page order).

0.1.6 — 2026-09-30

  • A product page where an offer came without a store link is read once more, and the more complete answer is kept.
  • isAtHistoryLow agrees with pctAboveHistoryLow: a price that rounds to 0% above the history low counts as at the low.

0.1.5 — 2026-09-30

  • Every row has the error field (null on product rows).

0.1.4 — 2026-09-30

  • Polish offer prices ("154,99 zł") are read; before, Polish offers had no price. Czech "Kč" prices follow the same rule (not tested on a Czech page yet).
  • Store links: a second source is used when Google's page has no direct link for an offer.

0.1.3 — 2026-09-30

  • Store links: tracking parameters placed after "#" are removed too.

0.1.2 — 2026-09-30

  • Price history coverage measured in 15 countries; Brazil is marked as a country without price history (like the UK and Turkey).
  • A product page without the price-history block is read once more in every country where Google was seen showing history.

0.1 — 2026-09-30

First version. See CHANGELOG.md.