# Google Shopping Price Comparison & Deal Finder (`vexaloom-labs/google-shopping-price-comparison-and-deal-finder`) Actor

Search Google Shopping by keyword and collect product prices, discounts, merchant names, ratings, and delivery info across 48 countries for price monitoring and deal tracking.

- **URL**: https://apify.com/vexaloom-labs/google-shopping-price-comparison-and-deal-finder.md
- **Developed by:** [vexaloom-labs](https://apify.com/vexaloom-labs) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Google Shopping Price Comparison & Deal Finder

Collect real Google Shopping data for price comparison and deal monitoring. Search by keyword, open a known product by its Google Shopping ID or viewer URL, browse a department, or pull current deals across 48 countries.

Search records use the actual product ID (`data-pid`) and a viewer link built from the catalog or product ID Google returns. Product-mode records carry the numeric ID used in the lookup and a working viewer link. Product records add seller offers with shipping and totals, a price range, specifications, images, variants, and the 12-month per-seller price history when Google exposes it.

### Modes

| Mode | What it does | Main input |
|---|---|---|
| **search** | Keyword search across Google Shopping results | `queries` |
| **product** | Opens the product viewer for one or more products | `productIds` |
| **deals** | Searches Google's deals view | `queries` (optional; defaults to `deals`) |
| **category** | Browses one of 15 Google Shopping departments | `category` |

### What you get

**Every record**

- `query`, `position`, `recordType`, `scrapedAt`
- `title`, `price` (display) and `priceValue` (number)
- `originalPrice`, `originalPriceValue`, `discountPercent` when discounted
- `currency` — the currency Google actually served, never relabelled from the requested country
- `merchant`, `merchantUrl`, `sellerDomain`
- `rating`, `reviewCount`, `ratingValue`, `reviewCountValue`
- `delivery`, `shipping`, `availability`, `condition`, `returns`
- `imageUrl`, `imageUrls`
- `isSponsored` (true only when a sponsored label is visible)
- `productId` — real `data-pid` on search/deals/category rows; in product mode it is the ID used in the viewer lookup (a catalog ID when the input is a viewer URL). `catalogId` is the real `data-cid` when Google exposes it.
- `productUrl` — a real Google Shopping viewer URL
- `searchUrl`, `hasMoreOffers`, `badge`

**Product records and enriched search results**

- `brand`, `description`, `images`, `specifications`, `variants`
- `offerCount` and `offers` — seller, seller ID, direct seller URL, domain, price, currency, original price, discount, shipping, delivery, total, availability, returns, store rating and review count, badge, best-price flag
- `lowestPrice`, `highestPrice`, `priceRange`, `typicalPriceRange`
- `priceHistory` — per-seller daily points with ISO dates
- `discussions` — forum links about the product (not review text)
- `dealFlags`

Empty fields are omitted at every depth.

### Inputs

| Field | Default | Description |
|---|---|---|
|---|---|
| `mode` | `search` | `search` (default), `product`, `deals` or `category` |
| `queries` | – | Keywords for search/deals. Optional in category mode |
| `productIds` | – | Catalog IDs, product IDs, viewer URLs or legacy product URLs for product mode |
| `category` | – | One of 15 departments (Electronics, Computers, Cell Phones, ...) |
| `countryCode` | `us` | 48 countries; sets the Google domain and location hint |
| `languageCode` | `en` | Result language |
| `sortBy` | – | Relevance, rating, price low-to-high or high-to-low; applied to the collected rows |
| `condition` | – | Any, new, used or refurbished |
| `minPrice` / `maxPrice` | – | Price range in the requested market's currency; rows outside the numeric bounds are dropped. If Google serves another currency, a filtered run can return no rows. |
| `onSale` | `false` | Keep products with an observed original price or discount |
| `freeShipping` | `false` | Keep products whose delivery text says free |
| `minRating` | `0` | 0–5; keeps products at or above the rating |
| `store` | – | Optional store name to bias and verify |
| `maxResultsPerQuery` | `20` | 1–200 records per query (or products in product mode) |
| `includePriceHistory` | `true` | Include the 12-month history when Google exposes it |
| `includeProductDetails` | `false` | Open the product viewer for each search result (one extra request per result) |

### Examples

Search for one product and include details and history:

```json
{
  "mode": "search",
  "queries": ["iPhone 15 Pro Max"],
  "maxResultsPerQuery": 5,
  "countryCode": "us",
  "includeProductDetails": true,
  "includePriceHistory": true
}
```

Look up products by ID or viewer URL:

```json
{
  "mode": "product",
  "productIds": ["10694224367759637585", "https://www.google.com/search?q=x&ibp=oshop&prds=productid:2457150560515047758,pvt:a"],
  "countryCode": "ca",
  "includePriceHistory": true
}
```

Price-filtered, free-shipping deals:

```json
{
  "mode": "deals",
  "queries": ["wireless earbuds"],
  "minPrice": 20,
  "maxPrice": 100,
  "freeShipping": true,
  "sortBy": "price_low",
  "countryCode": "uk"
}
```

Browse a department:

```json
{
  "mode": "category",
  "category": "electronics",
  "maxResultsPerQuery": 40,
  "countryCode": "de"
}
```

### Coverage and honest limits

- **Up to five offers per product.** Google's product viewer renders at most five offers over the public HTTP path (some products show fewer); `offerCount` often reports many more (209 in sampling). The remaining offers are not available without a browser identity.
- **About 127 products per query.** Search pages start at 0, 10, 50 and 90; later starts return no products. Split a broad query into narrower queries to collect more.
- **No product review text.** Google does not expose product review bodies on this path. Ratings and review counts from search cards and store ratings on offers are included; `discussions` contains forum links only.
- **Localization is best effort.** A country plus location hint usually returns the right market, but Google can serve another exit's currency. The actor retries once, then reports the actual `currency` and logs the mismatch. It never relabels one currency as another.
- **Filtered runs can be empty on a currency mismatch.** Price bounds use the requested market's currency (for example USD for `countryCode: us`). If Google serves another currency, a max-price or on-sale filter can exclude every row; the run then reports the served currency and fails with "No records scraped" instead of relabelling.
- **Sorting is client-side.** Google's server-side sort chip is not honored on this page. The actor sorts the rows it actually collected.
- **Filters are verified after collection.** Price bounds, rating, store, sale and free-shipping checks are re-applied to every row. A condition is checked when the card shows one; many cards omit it.
- **Display price can differ from the numeric offer price.** A seller card can show a list price in `price` while `priceValue` carries the best price Google reports (one sampled EarFun offer displayed `$89.99` with `priceValue` 51.29). Use `priceValue`, `shippingValue` and `totalPrice` for comparisons.
- **Sponsored detection is not a classifier.** `isSponsored` is true only when Google visibly labels a card as sponsored. Organic ads can appear without that label.
- **Some fields are source-dependent.** Brand, description, price history and typical price are present only when Google exposes them for that product. They are omitted rather than guessed.

### Practical use

- **Price monitoring:** run product mode on a fixed list of IDs and compare `priceValue`, `totalPrice` and `priceHistory` over time.
- **Deal scanning:** use deals mode with `onSale`, a price range and `sortBy: price_low`.
- **Market research:** search a category with `sortBy: review_score` and compare merchants, availability and shipping.
- **Catalog enrichment:** search with `includeProductDetails` to attach brand, images, specs and offers to keyword results.

### FAQ

**Do I need cookies, a login or a proxy setup?**
No. The actor reads public Google Shopping pages and handles its own access. There are no user credentials, cookies or proxy fields.

**Can I get every seller offer?**
No. Up to five offers per product is a hard limit of the public product viewer; the total count is returned so you know how many exist.

**Why is a field missing on some records?**
Google does not show every field on every card or product. Missing values are omitted; the actor does not fill them with guesses or sentinels.

**Why does the currency differ from the country I chose?**
Google's market routing is not guaranteed. The actor detects the served currency, retries once with the location hint, and reports the actual result rather than assuming.

**Can I sort by price?**
Yes — the actor sorts the collected rows by price or rating. The order is deterministic but reflects the rows collected, not Google's full index.

**Does this return product review text?**
No. Review text is not available on this path.

**Is this affiliated with Google?**
No. It is an independent third-party tool that reads publicly available Google Shopping pages.

# Actor input Schema

## `mode` (type: `string`):

What to collect: keyword search, product lookup by ID/viewer URL, deals, or a department category.

## `queries` (type: `array`):

Product keywords for search/deals mode. Ignored in product mode; optional in category mode.

## `productIds` (type: `array`):

Google Shopping catalog IDs, product IDs, product viewer URLs, or legacy /shopping/product/<id> URLs. Used in product mode.

## `category` (type: `string`):

Google Shopping department for category mode.

## `countryCode` (type: `string`):

Country used for the Google domain, UULE location and price hint. The actual currency is always detected from the response, never relabelled.

## `languageCode` (type: `string`):

Interface and result language (hl parameter).

## `sortBy` (type: `string`):

Client-side sort of the collected rows. Google ignores server-side sort on this page.

## `condition` (type: `string`):

Condition hint sent to Google and verified when the result card shows a condition.

## `minPrice` (type: `integer`):

Minimum price in the detected local currency. Applied through a shoprs filter and verified on every output row.

## `maxPrice` (type: `integer`):

Maximum price in the detected local currency. Applied through a shoprs filter and verified on every output row.

## `onSale` (type: `boolean`):

Ask Google for discounted products and keep rows with an observed original price or discount.

## `freeShipping` (type: `boolean`):

Ask Google for free-shipping products and keep rows whose delivery text says free.

## `minRating` (type: `string`):

Minimum product rating (0-5). Applied through a shoprs rating chip and verified on every output row.

## `store` (type: `string`):

Optional store name to bias and verify, e.g. Best Buy or Amazon.

## `maxResultsPerQuery` (type: `integer`):

Maximum records per query (search/deals/category) or products (product mode).

## `includePriceHistory` (type: `boolean`):

Include per-seller daily price history when Google exposes it (product mode and search detail enrichment).

## `includeProductDetails` (type: `boolean`):

Fetch the product viewer for each search result to add brand, description, images, specifications and offers. Costs one extra request per result.

## Actor input object example

```json
{
  "mode": "search",
  "queries": [
    "iPhone 15 Pro Max"
  ],
  "countryCode": "us",
  "languageCode": "en",
  "sortBy": "",
  "condition": "",
  "onSale": false,
  "freeShipping": false,
  "minRating": "0",
  "maxResultsPerQuery": 1,
  "includePriceHistory": true,
  "includeProductDetails": false
}
```

# Actor output Schema

## `products` (type: `string`):

Dataset containing search results, deals, category results and product records.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "search",
    "queries": [
        "iPhone 15 Pro Max"
    ],
    "countryCode": "us",
    "languageCode": "en",
    "onSale": false,
    "freeShipping": false,
    "maxResultsPerQuery": 1,
    "includePriceHistory": false,
    "includeProductDetails": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("vexaloom-labs/google-shopping-price-comparison-and-deal-finder").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "search",
    "queries": ["iPhone 15 Pro Max"],
    "countryCode": "us",
    "languageCode": "en",
    "onSale": False,
    "freeShipping": False,
    "maxResultsPerQuery": 1,
    "includePriceHistory": False,
    "includeProductDetails": False,
}

# Run the Actor and wait for it to finish
run = client.actor("vexaloom-labs/google-shopping-price-comparison-and-deal-finder").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "search",
  "queries": [
    "iPhone 15 Pro Max"
  ],
  "countryCode": "us",
  "languageCode": "en",
  "onSale": false,
  "freeShipping": false,
  "maxResultsPerQuery": 1,
  "includePriceHistory": false,
  "includeProductDetails": false
}' |
apify call vexaloom-labs/google-shopping-price-comparison-and-deal-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vexaloom-labs/google-shopping-price-comparison-and-deal-finder"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/MMwNfJSA1eG2IqVrJ/builds/p859CrahOaABt6Kkq/openapi.json
