# Google Shopping Scraper - Ads, Prices & Merchants (`chris_coussons/google-shopping-scraper`) Actor

Updated 7 Aug 2026. Google Shopping scraper and API for the PAID Shopping ads on Google Search, not the organic tab. ~5s per keyword, 20x faster. 47 fields: price, merchantDomain, landingPage, ratings, delivery, promotions + each merchant's CSS. Price monitoring and competitor analysis. UK/EU/US.

- **URL**: https://apify.com/chris\_coussons/google-shopping-scraper.md
- **Developed by:** [Chris Coussons](https://apify.com/chris_coussons) (community)
- **Categories:** E-commerce, Marketing, Lead generation
- **Stats:** 1 total users, 1 monthly users, 70.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 shopping ad scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Google Shopping Scraper - Ads, Prices & Merchants

**Updated 7 August 2026.**

A Google Shopping scraper and Google Shopping API alternative that returns the **paid Shopping ad carousel** from Google Search - not the organic Shopping tab.

Scrape Google Shopping results for any keyword and get **47 fields per ad** at around **5 seconds per keyword**, roughly 20x faster than comparable tools. Verified in the UK, Germany and the US.

Use it as an ecommerce price scraper, a Google Shopping results API, or a merchant discovery tool.

### What you can do with it

#### Competitor price monitoring

Track what every competing merchant charges for a product, including the was-price, discount percentage and unit price. Run the same keyword set daily to watch price movements across a category.

#### Google Shopping price API

Query any keyword and get structured pricing back - `price`, `priceValue`, `currency`, `currencyCode`, `originalPrice`, `discountPercent`, `pricePerUnitValue`. No feed access or merchant account needed.

#### Google Shopping competitor analysis

See which merchants advertise on your keywords, where they rank in the carousel, what promotions they run and how their delivery and returns terms compare to yours.

#### Merchant and lead discovery

Every row carries `merchantDomain` and `landingPage`, so a keyword sweep becomes a list of advertising merchants with their websites - usable for outreach, not just price tracking.

#### Comparison Shopping Service (CSS) research

In the UK, EEA and Switzerland, Google prints an attribution line on every Shopping ad - "By Google", "By Producthero", "By FeedOptimise". This scraper returns it as `cssProvider` and `cssType`. No other Google Shopping scraper does.

It tells you whether a merchant advertises through Google's own Comparison Shopping Service, where they pay up to 20% more per click, or through a Google CSS partner. Useful for CSS partners building prospect lists, and for agencies auditing client accounts.

### Why this scraper

**Fast.** About 4.7 seconds per keyword. Searches are batched inside a single warmed browser session rather than relaunching per keyword, which is where alternatives lose their time. A 40-keyword sweep returning 1,184 ads finishes in about three minutes.

**Deep.** 47 fields per ad, including merchant domain, landing page, Google's internal merchant and product IDs, unit pricing, delivery cost, returns policy and product condition.

**No solver account needed, nothing to sign up for.** Google's anti-bot interstitial is handled for you and included in the price. You never need a captcha-solving subscription, and the optional solver-key field can be left blank - it exists only for advanced users who prefer to bill solves to their own account.

**Built to keep running.** If a page misbehaves it retries through several approaches before giving up, every failed row carries a structured error code rather than failing silently, and it can email you when a run goes wrong.

**Common questions this answers:** Which merchants advertise on a keyword? What are competitors charging right now? Which merchant domains run Shopping ads in my category? Which Comparison Shopping Service does a merchant use? How do desktop and mobile Shopping ads differ?

### Output fields

One row per ad. Every field below is returned; fields Google only shows on certain listings return `null` when absent.

#### Product

| Field | Type | Description |
|---|---|---|
| `productTitle` | string | Full product title as shown on the ad |
| `productId` | string | Google's offer/product identifier |
| `productImage` | string | Product image (data URI or URL) |
| `condition` | string | New, Refurbished, Used, Pre-owned or Open box |

#### Pricing

| Field | Type | Description |
|---|---|---|
| `price` | string | Displayed price, e.g. `£339.00` |
| `priceValue` | number | Numeric price, e.g. `339` |
| `currency` | string | Currency symbol, e.g. `£` |
| `currencyCode` | string | ISO code, e.g. `GBP` |
| `originalPrice` | string | Pre-discount price when shown |
| `originalPriceValue` | number | Numeric pre-discount price |
| `discountPercent` | number | Calculated discount percentage |
| `checkoutPrice` | string | Total or checkout price when shown |
| `checkoutPriceValue` | number | Numeric checkout price |
| `pricePerUnitText` | string | Unit pricing, e.g. `£2.80/1kg` |
| `pricePerUnitValue` | number | Numeric unit price |

#### Merchant

| Field | Type | Description |
|---|---|---|
| `merchant` | string | Merchant name |
| `merchantDomain` | string | Merchant website domain |
| `merchantId` | string | Google's internal merchant identifier |
| `landingPage` | string | Direct product URL on the merchant site |
| `googleAdUrl` | string | Google ad click URL |

#### Fulfilment

| Field | Type | Description |
|---|---|---|
| `deliveryText` | string | Delivery line, e.g. `Free by 12/08` |
| `deliveryCost` | number | Numeric delivery cost, `0` when free |
| `freeShipping` | boolean | Whether delivery is free |
| `clickAndCollect` | boolean | Whether collection is offered |
| `returnsText` | string | Returns policy, e.g. `30-day returns` |

#### Ratings

| Field | Type | Description |
|---|---|---|
| `rating` | number | Product rating out of 5 |
| `reviewCount` | number | Number of product reviews |
| `storeRating` | number | Merchant store rating out of 5 |
| `storeReviewCount` | number | Number of store reviews |

#### Promotions and badges

| Field | Type | Description |
|---|---|---|
| `saleLabel` | string | e.g. `SALE`, `Special offer` |
| `priceDropLabel` | string | Price drop indicator |
| `promotionText` | string | e.g. `Save 10% when you subscribe` |
| `promotionCode` | string | Voucher code when shown |
| `promotionDiscountPercent` | number | Promotion percentage |
| `badge` | string | e.g. `Trending brand` |
| `topQualityStoreBadge` | boolean | Google Top Quality Store badge |

#### Comparison Shopping Service

| Field | Type | Description |
|---|---|---|
| `cssProvider` | string | The CSS named on the ad, e.g. `Google`, `Producthero`, `FeedOptimise` |
| `cssType` | string | `google`, `partner`, or `label_not_read` |

`cssType` is never inferred. If the label could not be read, the row says `label_not_read` rather than guessing.

#### Context

| Field | Type | Description |
|---|---|---|
| `searchQuery` | string | Keyword that produced the ad |
| `position` | number | Ad position for that keyword |
| `device` | string | `desktop` or `mobile` |
| `country` | string | Market code used |
| `language` | string | Language code used |
| `detectedLocation` | string | Location Google reported for the request |
| `scrapedAt` | string | Timestamp |
| `id` | string | Stable row identifier |
| `adCardScreenshot` | string | PNG URL, when screenshots are enabled |

### Input

| Field | Default | Description |
|---|---|---|
| `searchQueries` | - | Buyer keywords, one per line (required) |
| `googleDomain` | `www.google.co.uk` | Google front end to search |
| `countryCode` | `gb` | Market targeting |
| `languageCode` | `en` | Language |
| `device` | `desktop` | `desktop` or `mobile` |
| `location` | - | Optional city or postal area for local ads |
| `maxAdsPerQuery` | `40` | Cap per keyword |
| `maxTotalAds` | `0` | Overall cap, 0 for no cap |
| `queriesPerSession` | `8` | Searches per browser session - higher is faster and cheaper |
| `proxyType` | `RESIDENTIAL` | `RESIDENTIAL` or `DATACENTER` |
| `captureScreenshots` | `false` | Save a PNG of each ad card |
| `capsolverApiKey` | - | **Not required - leave blank.** Solving is included. Only for advanced users who want solves billed to their own account |

### Example

```json
{
  "searchQueries": ["oak sideboard", "wireless headphones"],
  "countryCode": "gb",
  "device": "desktop",
  "maxAdsPerQuery": 40
}
```

Returns rows like:

```json
{
  "searchQuery": "oak sideboard",
  "position": 1,
  "productTitle": "Ancroft Waxed Oak 3 Door 3 Drawer Large Sideboard",
  "price": "£339.00",
  "priceValue": 339,
  "currencyCode": "GBP",
  "merchant": "Oak World",
  "merchantDomain": "oakworld.co.uk",
  "landingPage": "https://www.oakworld.co.uk/shop/sideboards/ancroft-oak-large-sideboard/",
  "deliveryText": "Free by 12/08",
  "freeShipping": true,
  "condition": "New",
  "cssProvider": "Producthero",
  "cssType": "partner"
}
```

### Use cases

- Competitive price monitoring across merchants and keywords
- Shopping ad rank and share-of-voice tracking
- Merchant and lead discovery with domains and landing pages
- Promotion, discount and unit-price tracking
- Desktop versus mobile Shopping ad comparison
- Finding merchants on Google's own CSS who are overpaying per click
- Building switch lists for CSS partners and feed agencies
- Auditing which CSS a brand advertises through

### Benchmarks

Measured on live results.

**Speed and scale (UK):** 40 keywords, 1,184 ads, 188 seconds end to end - about 4.7 seconds per keyword. 93% of ads carried a readable CSS label, 97.8% of merchants resolved, and every merchant returned the same CSS across every keyword it appeared on.

**Verified across markets:**

| Market | Ads | Errors | Currency | CSS attribution |
|---|---|---|---|---|
| UK (google.co.uk) | 40 | 0 | GBP | 39 of 40 labelled |
| Germany (google.de) | 60 | 0 | EUR | 49 of 60 labelled |
| US (google.com) | 58 | 0 | USD | n/a - no CSS programme |

European number formats are handled (`41,95 €` parses to `41.95`), and attribution is read in English, German, French and Spanish. In the US every field works except CSS, which does not exist there.

### Also known as

Paid Shopping ads are also called product listing ads or PLAs. People look for this kind of tool as a Google Shopping scraper, a Google Shopping API, a Google Shopping results API, a Google Shopping search API, a way to scrape Google Shopping results, or an ecommerce price scraper. This Actor covers all of those, for paid ad data specifically.

### Notes

CSS attribution exists only in the UK, EEA and Switzerland, where the Comparison Shopping Service remedy applies. All other fields work in every Google market.

Unit pricing, checkout price, promotion codes and price-drop labels are card features Google shows selectively. They populate when present - unit pricing fills on roughly a third of consumable listings and correctly returns null on categories like furniture.

# Actor input Schema

## `searchQueries` (type: `array`):

Buyer keywords to check for paid Shopping ads, e.g. oak dining table

## `googleDomain` (type: `string`):

Which Google front end to search

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

Two letter country code for geo targeting

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

Two letter language code

## `device` (type: `string`):

Which Google surface to scrape - desktop or mobile ads can differ

## `location` (type: `string`):

City or postal area for locally targeted Shopping ads

## `maxAdsPerQuery` (type: `integer`):

Cap on Shopping ads saved per keyword

## `maxTotalAds` (type: `integer`):

Overall cap across all keywords (0 = no cap)

## `captureScreenshots` (type: `boolean`):

Save a PNG of each ad card - slower, useful for visual verification

## `notifyEmail` (type: `string`):

Email to notify if a run fails badly. Leave blank for no alerts.

## `failureAlertThreshold` (type: `integer`):

Send the alert when this share of keywords fails

## `queriesPerSession` (type: `integer`):

How many searches to run per solved session - higher amortises the captcha solve

## `proxyType` (type: `string`):

RESIDENTIAL (fewer captchas, dearer) or DATACENTER (cheap, more solves)

## `proxyCountry` (type: `string`):

Country for the residential proxy exit node - should match the market being scraped

## `capsolverApiKey` (type: `string`):

Leave this blank. Captcha solving is already included at no extra cost and needs no account from you. This field exists only for advanced users who want solves billed to their own CapSolver account instead.

## Actor input object example

```json
{
  "searchQueries": [
    "oak dining table"
  ],
  "googleDomain": "www.google.co.uk",
  "countryCode": "gb",
  "languageCode": "en",
  "device": "desktop",
  "location": "",
  "maxAdsPerQuery": 40,
  "maxTotalAds": 0,
  "captureScreenshots": false,
  "notifyEmail": "",
  "failureAlertThreshold": 25,
  "queriesPerSession": 8,
  "proxyType": "RESIDENTIAL",
  "proxyCountry": "GB"
}
```

# 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 = {
    "searchQueries": [
        "oak dining table"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("chris_coussons/google-shopping-scraper").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 = { "searchQueries": ["oak dining table"] }

# Run the Actor and wait for it to finish
run = client.actor("chris_coussons/google-shopping-scraper").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 '{
  "searchQueries": [
    "oak dining table"
  ]
}' |
apify call chris_coussons/google-shopping-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,chris_coussons/google-shopping-scraper"
        }
    }
}

```

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/gsQR9WXerZwfO7cRW/builds/IZt81ifokH1wOQICa/openapi.json
