# Google Shopping Scraper (`hebaabdalaziz/google-shopping-scraper`) Actor

Scrape Google Shopping product results for any search query or pasted Google Shopping URL in any country and language. Get title, price, old price, discount, merchant, rating, review count and delivery info. No login, pay per result.

- **URL**: https://apify.com/hebaabdalaziz/google-shopping-scraper.md
- **Developed by:** [Heba Abdalaziz](https://apify.com/hebaabdalaziz) (community)
- **Categories:** E-commerce, SEO tools, Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 89.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.50 / 1,000 products

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/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

### What does Google Shopping Scraper do?

**Google Shopping Scraper** collects the product results that [Google Shopping](https://shopping.google.com) shows for any search query, in any country and language. For every product card you get the title, current price (as a number plus its currency), old price and discount badge, the shop selling it, whether more shops sell it, delivery or returns notes, star rating, review count and Google's own product ids.

Enter keywords such as `running shoes`, or paste Google Shopping result URLs with filters already applied, and download the results as JSON, CSV, Excel or HTML, or use them through the Apify API.

### Why use it?

- **Price monitoring**: track the prices and discounts for your products and your competitors' products.
- **Market research**: see which brands, shops and products Google Shopping ranks for a keyword in each country.
- **Assortment and MAP checks**: find who sells a product, at what price, and with which delivery terms.
- **Any country, any language**: prices are parsed per locale (`$1,299.00`, `1.299,00 €`, `₹2,499`, `￥30,999`) into plain numbers with an ISO currency code.
- **Fast and light**: no browser, just HTTP requests, so runs start quickly and stay cheap.

### How to use it

1. Click **Try for free** (or **Start**) on this page.
2. In **Search queries or Google Shopping URLs**, enter one keyword or URL per line.
3. Set **Country** and **Language** (for example `de` and `de` for Germany) and how many products you want per query.
4. Click **Start** and wait - a query with 100 products usually takes 15-40 seconds.
5. Open the **Output** tab to preview the products and export them in the format you need.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `queries` | array of strings | - (required) | Keywords, or Google Shopping URLs (`google.*/search?...&udm=28` or `tbm=shop`). The `q`, `gl`, `hl` and filter parameters (`tbs`, `shoprs`, ...) of a URL are kept. |
| `country` | string | `us` | Two-letter country code (Google `gl`). A `gl` inside a URL wins; a URL without `gl` uses the country of its Google domain (google.de = `de`). |
| `language` | string | `en` | Interface language code (Google `hl`). An `hl` inside a URL wins. |
| `maxProductsPerQuery` | integer | `100` | Unique products to collect per query (1-300). |
| `maxPagesPerQuery` | integer | `10` | Result pages to request per query (1-10). About 3 pages give 100 products, 8-10 pages give 300. |
| `saveRawHtml` | boolean | `false` | Debugging only: stores every fetched page in the key-value store. |

Example input:

```json
{
    "queries": [
        "running shoes",
        "https://www.google.com/search?q=kaffeemaschine&udm=28&gl=de&hl=de"
    ],
    "country": "us",
    "language": "en",
    "maxProductsPerQuery": 100,
    "maxPagesPerQuery": 10
}
```

### Output

Each product is one row in the dataset. A real row from a cloud run:

```json
{
    "position": 1,
    "page": 1,
    "query": "running shoes",
    "country": "us",
    "language": "en",
    "productId": "4196561114474179181",
    "offerId": "17147103039274595891",
    "pid": "17366988515004433012",
    "title": "Asics Gel-Kayano 14",
    "price": 129.95,
    "currency": "USD",
    "priceText": "$129.95",
    "oldPrice": 150,
    "discountBadge": "13% OFF",
    "merchant": "ASICS",
    "moreMerchants": true,
    "delivery": "Free 90-day returns",
    "rating": 4.8,
    "reviewCount": 2200,
    "searchUrl": "https://www.google.com/search?q=running+shoes&udm=28&gl=us&hl=en",
    "input": "running shoes",
    "scrapedAt": "2026-10-10T11:58:23+00:00"
}
```

Inputs that could not be used or that failed (invalid URL, blocked after all retries), and queries that stopped early at a later page, are listed in the `FAILED_INPUTS` record of the run's key-value store as `[{"input": ..., "reason": ...}]`. Failed inputs cost nothing; a query that stopped early is charged only for the products it returned.

### Data fields

| Field | Type | Description |
|---|---|---|
| `position` | integer | Rank within the query (1 = first), across pages, duplicates removed |
| `page` | integer | Result page the product was found on |
| `query` | string | Search query |
| `country` | string | Country code the search ran for (`gl`) |
| `language` | string | Interface language (`hl`) |
| `productId` | string or null | Google catalog product id (`cid`); null for single-shop offers Google has not grouped into a product |
| `offerId` | string or null | Google offer id (`oid`) of the offer shown |
| `pid` | string or null | Google product id (`pid`) of the card |
| `title` | string | Product title |
| `price` | number | Current price |
| `currency` | string or null | ISO 4217 currency code |
| `priceText` | string | Price as displayed, e.g. `59,99 €`, or `$19+` for a "from" price |
| `oldPrice` | number or null | Previous / usual price when discounted |
| `discountBadge` | string or null | Image badge such as `15% OFF`, `LOW PRICE`, `SALE` |
| `merchant` | string or null | Shop shown on the card (null when the card only says "& more") |
| `moreMerchants` | boolean | `true` when more shops sell the product |
| `delivery` | string or null | Delivery or returns note, e.g. `Free delivery · 30-day returns` |
| `rating` | number or null | Average rating out of 5 |
| `reviewCount` | integer or null | Number of reviews (Google rounds big numbers: `1.9K` = 1900) |
| `searchUrl` | string | Result page the row came from |
| `input` | string | The query or URL from your input |
| `scrapedAt` | string | ISO 8601 timestamp (UTC) |

### How much does it cost?

The Actor uses **pay-per-result** pricing: you pay **$1.50 per 1,000 products** ($0.0015 per product) saved to the dataset. There is no start fee, and queries that return nothing or fail cost nothing. Proxy and compute costs are included.

| Products | Price |
|---|---|
| 100 | $0.15 |
| 1,000 | $1.50 |
| 10,000 | $15.00 |

You can cap the spend of a run with the **Maximum cost per run** setting; the Actor stops cleanly when it is reached.

### Tips

- **Filters**: open Google Shopping in your browser, apply filters (price range, brand, on sale, free delivery, ...) and paste the resulting URL as a query - all filters are kept.
- **Depth**: Google Shopping shows up to about 8 pages (roughly 250-300 unique products) per query. Each page adds 25-40 new products.
- **Local results**: set `country` and `language` together (e.g. `fr`/`fr`, `in`/`en`, `jp`/`ja`) to get local shops and prices in the local currency.
- **Many queries**: put them all in one run; up to 3 queries are processed in parallel. Duplicate searches are skipped, so you never pay twice for the same query.

### FAQ

**Is it legal to scrape Google Shopping?**
The Actor only collects publicly visible product listings (titles, prices, shops, ratings). It does not log in and does not collect personal data. Still, you are responsible for how you use the data; check Google's terms and your local laws, and consult a lawyer if you are unsure.

**Does it collect personal data?**
No. Product cards contain product and shop information only; review texts and reviewer names are not collected.

**Why is `productId` sometimes null?**
Google shows some single-shop offers that it has not grouped into a catalog product. Those rows still have `offerId` and `pid`, and duplicates are removed by those ids.

**Why are there fewer products than I asked for?**
Google Shopping returns a limited number of products per query (about 300 at most). The Actor stops when a page brings no new products.

**What happens with a misspelled or nonsense query?**
Google decides. If it replaces your query with a corrected one ("Showing results for ..."), the Actor returns those products and adds a note with the corrected query to the run's status message. For a nonsense query (random letters) Google usually still shows a generic feed of popular products: the Actor returns that feed as it is, and **those rows are billed like any other**, so check your queries before large runs. Only a query with no product cards at all returns nothing and costs nothing.

**What if Google shows results for another country?**
The proxy often answers from another location, especially for google.com. The Actor checks the price currencies (and, as a backup, shop domains) against the country you asked for and retries with a new IP, up to 6 times per page (within about 45 seconds). If a page still comes from another location, it is skipped and **never billed**: the query keeps the products already collected and is listed in `FAILED_INPUTS` with "stopped at page N: results kept coming from another location". Exception: for a country the Actor has no local Google domain or currency for (e.g. `lu`), once the same foreign currency keeps coming back for 2 different queries (or at the first failure when the Actor knows no currency for the country), the Actor accepts that location from then on and warns in the status message that prices may not be local.

**Are the images included?**
No. Google embeds thumbnails inline as data, not as image links, so they are not part of the output.

### Support

Found a bug or need another field? Open an issue in the **Issues** tab of this Actor and include the link to the run.

# Actor input Schema

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

What to search on Google Shopping. Enter keywords (e.g. <code>running shoes</code>) or paste full Google Shopping result URLs - the query, country (<code>gl</code>), language (<code>hl</code>) and any filters (price range, brand, on sale, ... in <code>tbs</code> / <code>shoprs</code>) in the URL are kept. A pasted URL without <code>gl</code> uses the country of its Google domain (e.g. google.de = Germany). Duplicate searches are skipped.

## `country` (type: `string`):

Two-letter country code Google Shopping should search in (Google's <code>gl</code> parameter), e.g. <code>us</code>, <code>gb</code>, <code>de</code>, <code>in</code>, <code>fr</code>. Prices and shops follow this country. A <code>gl</code> inside a pasted URL wins.

## `language` (type: `string`):

Interface language code (Google's <code>hl</code> parameter), e.g. <code>en</code>, <code>de</code>, <code>fr</code>, <code>es</code>. An <code>hl</code> inside a pasted URL wins.

## `maxProductsPerQuery` (type: `integer`):

Stop after this many unique products for each query. Google Shopping usually has up to about 300 products per query.

## `maxPagesPerQuery` (type: `integer`):

Upper bound on result pages requested per query (each page adds about 25-40 new products; 300 products need about 8-10 pages). The scraper stops earlier as soon as the product limit is reached or a page brings no new products, so the default rarely costs extra.

## `saveRawHtml` (type: `boolean`):

Store every fetched result page in the run's key-value store (keys starting with RAW-). Only useful for debugging.

## Actor input object example

```json
{
  "queries": [
    "running shoes"
  ],
  "country": "us",
  "language": "en",
  "maxProductsPerQuery": 20,
  "maxPagesPerQuery": 10,
  "saveRawHtml": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `failedInputs` (type: `string`):

No description

# 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 = {
    "queries": [
        "running shoes"
    ],
    "maxProductsPerQuery": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("hebaabdalaziz/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 = {
    "queries": ["running shoes"],
    "maxProductsPerQuery": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("hebaabdalaziz/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 '{
  "queries": [
    "running shoes"
  ],
  "maxProductsPerQuery": 20
}' |
apify call hebaabdalaziz/google-shopping-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hebaabdalaziz/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/yFjySJak7S8lZWEYu/builds/J1UxB34ig8rK6gqVo/openapi.json
