# Google Shopping Scraper - Extra Offers (`scrapers-hub/google-shopping-scraper-extra-offers`) Actor

Google Shopping Scraper - Extra Offers retrieves merchant offers by EAN or SKU - title, brand, thumbnail, currency, offer count and lowest and highest total price with freshness timestamps. 🏷️ For price comparison and MAP monitoring.

- **URL**: https://apify.com/scrapers-hub/google-shopping-scraper-extra-offers.md
- **Developed by:** [Scrapers Hub](https://apify.com/scrapers-hub) (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 $1.99 / 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.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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 – Extra Offers, Seller Prices & EAN Lookup

The Google Shopping Scraper – Extra Offers takes a list of product identifiers, looks each one up on Google Shopping for a chosen country, and returns a structured offer record containing every seller listing it finds. Rather than a page of search results, you get a normalised object per product: the product title and brand, the currency, the number of offers, the full offers array, and the lowest and highest total prices across those offers.

This Google Shopping scraper is aimed at price monitoring, marketplace intelligence and retail analytics workflows where the unit of analysis is a product rather than a keyword. You feed it EANs or product codes, one per line, and it produces a dataset you can join straight onto your own catalogue. Each record is stamped with the country code it was checked against and a timestamp, so historical price series stay unambiguous.

***

### 📊 What Data Can You Extract with This Google Shopping Scraper?

Every record returned by the Google Shopping scraper covers six areas: how the product was identified, whether the lookup succeeded, what the product is, what the offers look like, how prices are distributed, and when the check happened.

| Category | Fields | What it tells you |
|---|---|---|
| 🔖 Product identifiers | `ean`, `sku` | The identifier you supplied and any stock keeping unit associated with the record |
| 🌍 Market context | `gl`, `currency` | The country code the lookup targeted and the currency the prices are quoted in |
| ✅ Lookup outcome | `found`, `status`, `no_offers_found`, `message` | Whether the product resolved, what state the check ended in, and a human-readable explanation |
| 🧾 Product attributes | `title`, `brand`, `url`, `thumbnail` | The product name, its brand, the canonical URL for the lookup and a thumbnail image |
| 💰 Offers and pricing | `offers`, `offers_count`, `lowest_total_price`, `highest_total_price` | The full array of seller offers plus the count and the price envelope across them |
| ⏱️ Freshness | `checked_at`, `fetched_at`, `age_hours` | When the product was checked, when the page was fetched and how old the data is in hours |

The most operationally useful pairing is `lowest_total_price` with `offers_count`. A low floor price backed by many offers means a genuinely competitive product where undercutting is expensive; a low floor with one or two offers usually means a single aggressive seller you can monitor individually.

***

### 🌟 Key Features of the Google Shopping Scraper

| Feature | Description |
|---|---|
| 🔢 Identifier-driven lookups | Supply products as a newline-separated list in the `products` field; each line is looked up independently and returned as its own dataset record |
| 🌐 Country targeting | The `country` input sets the Google Shopping locale (`gl`), so prices and available sellers reflect the market you actually sell in |
| 📦 Full offers array | The `offers` field carries the seller-level detail behind the summary numbers, rather than only a single headline price |
| 📉 Price envelope | `lowest_total_price` and `highest_total_price` are computed across the offers so you get the spread without post-processing |
| 🚦 Explicit outcome flags | `found`, `status` and `no_offers_found` distinguish "product not resolved" from "resolved but no sellers listed" — two very different situations |
| 💬 Diagnostic messages | The `message` field explains unusual outcomes in plain language, which makes triaging a large batch far quicker |
| ⏱️ Freshness metadata | `checked_at`, `fetched_at` and `age_hours` are attached to every record, so downstream systems can decide whether to trust or refresh a value |
| 🔁 Force refresh flag | The `force` input lets you re-run a lookup rather than accepting a previously cached outcome |
| 🧱 Stable record shape | Every product returns the same keys whether or not offers were found, so the dataset loads cleanly into a fixed-schema table |

***

### 🚀 Why Choose This Google Shopping Scraper?

**Product-level, not keyword-level.** Keyword scrapers give you whatever Google decides is relevant. This actor works from identifiers you control, so each row maps deterministically onto a row in your own product master. That is the difference between a research dump and a dataset you can join.

**The offer spread comes precomputed.** Most pipelines end up recalculating minimum and maximum totals from a raw offers list. Here `lowest_total_price` and `highest_total_price` arrive alongside `offers_count`, so a simple dashboard needs no transformation layer at all.

**Failure states are first-class data.** `found`, `status`, `no_offers_found` and `message` mean an unsuccessful lookup still produces a usable record. You can measure your own coverage — how many catalogue items Google actually lists in a given country — instead of silently losing rows.

**Country is explicit on every row.** Because `gl` and `currency` are stored per record, you can run the same product list against several markets and stack the results in one table without ambiguity about which price belongs to which country.

***

### 📥 Input

```json
{
  "products": "8720648364181\n8712345678901\n4006381333931",
  "country": "NL",
  "force": false
}
```

#### 🔧 Google Shopping Scraper Input Fields

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `products` | string | Yes | `""` | Product identifiers to look up, one per line. Blank lines are ignored. If no products are supplied the run ends immediately. |
| `country` | string | No | `NL` | Country code used as the Google Shopping locale for the lookup. It is lower-cased and returned on each record as `gl`. |
| `force` | boolean | No | `false` | Force the lookup to run rather than accepting a previously stored result. |

#### 💡 Input Examples

**Single-market price check**

```json
{
  "products": "8720648364181",
  "country": "NL"
}
```

**Batch of catalogue EANs for the German market**

```json
{
  "products": "4006381333931\n4008110018751\n4005808756919",
  "country": "DE",
  "force": true
}
```

**United States lookup**

```json
{
  "products": "0885909950805\n0194252099216",
  "country": "US",
  "force": false
}
```

***

### 📤 Output

```json
{
  "ean": "8720648364181",
  "sku": null,
  "gl": "nl",
  "found": true,
  "status": "scraped",
  "title": "Example Product Name",
  "brand": "ExampleBrand",
  "url": "https://www.google.com/search?q=8720648364181&tbm=shop&gl=nl",
  "thumbnail": "https://example.com/thumbnail.jpg",
  "currency": "EUR",
  "fetched_at": "2026-08-11T09:14:02.481Z",
  "age_hours": 0.0,
  "offers_count": 2,
  "offers": [
    {
      "sellerName": "Store A",
      "sellerReference": "https://example.com/store-a",
      "price": "34.95",
      "shippingPrice": null,
      "totalPrice": "34.95",
      "condition": "New",
      "availability": "InStock"
    }
  ],
  "lowest_total_price": 34.95,
  "highest_total_price": 39.95
}
```

When a product resolves but Google Shopping lists no sellers, the record instead carries `status` set to a no-offers state, `no_offers_found` set to `true`, an empty `offers` array, `offers_count` of `0`, and an explanatory `message`.

#### 🧾 Google Shopping Output Fields

| Field | Type | Description |
|---|---|---|
| `ean` | string | null | Ean of the item. |
| `sku` | string | null | Stock keeping unit. |
| `gl` | string | null | Gl of the item. |
| `found` | boolean | null | Whether found. |
| `status` | string | null | Status of the item. |
| `no_offers_found` | boolean | null | Whether no offers found. |
| `message` | string | null | Message of the item. |
| `title` | string | null | Title of the item. |
| `brand` | string | null | Brand name. |
| `url` | string | null | Canonical URL of the scraped item. |
| `thumbnail` | string | null | Thumbnail image URL. |
| `currency` | string | null | Currency code of the price. |
| `checked_at` | string | null | When the checked happened. |
| `age_hours` | number | null | Age hours of the item. |
| `offers_count` | integer | null | Number of offers. |
| `offers` | array | null | Offers values collected for the item. |
| `fetched_at` | string | null | When the page was fetched. |
| `lowest_total_price` | number | null | Lowest total price of the item. |
| `highest_total_price` | number | null | Highest total price of the item. |

#### 🧾 Offer Object Fields

Each entry inside the `offers` array describes a single seller listing:

| Field | Description |
|---|---|
| `sellerName` | Name of the merchant making the offer |
| `sellerReference` | Reference URL for the merchant or the offer |
| `price` | Item price excluding shipping |
| `shippingPrice` | Shipping cost, where one is stated |
| `totalPrice` | Item price plus shipping |
| `condition` | Stated condition of the item, such as New |
| `availability` | Stock status reported by the merchant |

***

### 💻 How to Use the Google Shopping Scraper (Step by Step)

#### Step 1: Assemble your product identifier list

The `products` field takes a plain block of text with one identifier per line. Export the identifier column from your product information system, paste it into the field, and the actor splits it on newlines and trims whitespace automatically. Empty lines are skipped, so a trailing blank line at the end of a paste is harmless. If the field ends up empty, the run finishes immediately without producing any records — a useful sanity check if you ever see an empty dataset.

#### Step 2: Choose the target country

`country` decides which Google Shopping locale is queried and therefore which merchants and currency appear in the results. It defaults to `NL`. Whatever you pass is lower-cased and echoed back on every record as `gl`, which is what makes multi-market datasets safe to stack. If you sell in several countries, run the same product list once per country rather than mixing markets in a single run.

#### Step 3: Decide whether to force a refresh

The `force` flag controls whether the actor performs a fresh lookup or is willing to return a previously stored outcome. Leave it `false` for routine monitoring where a slightly older value is acceptable, and set it `true` when you are investigating a specific pricing anomaly and need to be certain the numbers reflect the present moment. The `age_hours` field on each record tells you how stale the returned data is.

#### Step 4: Start the run and watch the log

Launch the actor from the Apify Console or the API. The run log reports how many products were parsed from your input and the country being used, then logs each product as it is processed. If a lookup fails at the HTTP level, the log records the status code for that specific product and continues to the next one, so a single problematic identifier does not abort the whole batch.

#### Step 5: Interpret the outcome flags before the prices

Before you analyse pricing, split the dataset on `found` and `no_offers_found`. Records where `found` is false never resolved to a product at all — usually an identifier problem on your side. Records where `no_offers_found` is true resolved fine but had no sellers in that country, which is a genuine market-coverage finding rather than an error. Only the remaining rows carry meaningful `offers` data.

#### Step 6: Work with the offers array

`offers_count` gives you the headline, but the real detail sits in the `offers` array. Each entry names a seller, states a price, a shipping price and a total, and reports condition and availability. Flatten this array into a separate table keyed on `ean` if you want per-seller time series; keep it nested if you only need the summary figures, which are already available as `lowest_total_price` and `highest_total_price`.

#### Step 7: Export, schedule and integrate

Export the dataset as CSV, JSON, XLSX or XML from the Console, or read it through the dataset API. For ongoing price monitoring, attach an Apify **Schedule** to run the same product list at a fixed cadence, and use a webhook to notify your own systems when each run completes so a downstream job can pick up the new snapshot automatically.

***

### 🔌 API Access & Integrations

Trigger a Google Shopping scraping run and get the dataset items back in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/scrapers-hub~google-shopping-scraper-extra-offers/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "products": "8720648364181\n4006381333931",
    "country": "NL",
    "force": false
  }'
```

The equivalent using the Python client:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")

run = client.actor("scrapers-hub/google-shopping-scraper-extra-offers").call(run_input={
    "products": "8720648364181\n4006381333931\n4008110018751",
    "country": "NL",
    "force": True,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["ean"], item["offers_count"], item["lowest_total_price"])
```

Finished datasets connect to Zapier, Make, Google Sheets and Slack, and Apify webhooks can call your own endpoint the instant a Google Shopping run completes.

***

### 💡 Best Use Cases for Google Shopping Offers Data

#### 💰 Competitive price monitoring

Run your catalogue EANs daily and track `lowest_total_price` per product over time. Because `totalPrice` inside each offer already includes shipping where stated, you are comparing landed prices rather than headline prices, which is what a shopper actually decides on. Alert when the floor drops below your own listed price.

#### 🗺️ Cross-border market coverage

Execute the same `products` list against several `country` values and compare `found` and `no_offers_found` rates. Products that resolve everywhere but only attract offers in one market show you where distribution is thin, and the `gl` field on each record keeps the markets cleanly separated in a stacked table.

#### 🧮 Price dispersion analysis

The gap between `lowest_total_price` and `highest_total_price`, divided by `offers_count`, is a quick proxy for how disciplined a product's pricing is. Wide dispersion across many offers often signals grey-market supply or inconsistent MAP enforcement, and is worth investigating seller by seller in the `offers` array.

#### 🏪 Seller and reseller discovery

Flatten the `offers` array and group by `sellerName` to build a list of every merchant carrying your products. `sellerReference` gives you the link to follow up, and `availability` tells you whether they hold stock or are listing without inventory.

#### 📋 Catalogue data enrichment

Where your own product records are incomplete, `title`, `brand` and `thumbnail` provide reference values you can use to fill gaps or validate existing entries. Comparing the returned `brand` against your master data is also an effective way to catch mis-keyed identifiers.

#### 🕰️ Data freshness governance

`checked_at`, `fetched_at` and `age_hours` let you enforce a service-level rule in your own pipeline: refresh anything older than a threshold, and flag anything stale in your reporting layer. Combined with the `force` input, this makes selective refreshes straightforward.

#### 🚨 Availability and stock-out tracking

The `availability` value inside each offer, read alongside `offers_count` and `no_offers_found`, gives you an early-warning signal for products disappearing from a market. A product whose offer count falls steadily towards zero is losing distribution before it shows up in your own sales data.

***

### ⚙️ Tips for Better Google Shopping Scraping Results

- **Clean identifiers before submitting them.** Strip spaces, hyphens and leading apostrophes that spreadsheet exports often add. A malformed EAN is the single most common reason for a `found` value of false.
- **Keep one country per run.** Mixing markets in a single job makes the dataset harder to reason about; separate runs per `country` value keep both the input and the resulting time series clean.
- **Batch sensibly.** Very large single blocks in `products` produce long runs. Splitting a large catalogue into several runs makes failures easier to isolate and reruns cheaper.
- **Use `force` sparingly.** Forcing a refresh on every product on every run removes the benefit of stored results. Reserve it for investigations and for products where `age_hours` exceeds your tolerance.
- **Store `checked_at` with every snapshot.** When you append runs into a historical table, the timestamp is what turns a pile of rows into a usable price series.
- **Separate no-offer records early.** Filter on `no_offers_found` before computing averages, otherwise products with zero sellers will quietly skew your aggregates.

***

### 🛠️ Troubleshooting

**The run finished but the dataset is empty.**
The actor exits immediately when no products are parsed from the input. Check that `products` actually contains text and that lines are separated by real newlines rather than commas or semicolons.

**A product returns `found` as false.**
The identifier did not resolve. Verify the EAN or code against your source system, confirm there are no stray characters, and check whether the product is sold in the country you targeted at all.

**A product returns `no_offers_found` as true.**
This is not an error. The lookup succeeded but Google Shopping listed no sellers for that product in that country. The `message` field explains the outcome. Try a different `country` value if you expect the product to be available elsewhere.

**Some products are missing from the dataset entirely.**
If a lookup fails at the HTTP level the actor logs the failing status code for that product and moves on rather than pushing a record. Check the run log for those entries and re-submit just those identifiers.

**Prices look stale.**
Inspect `age_hours` on the affected records. If the value is higher than you want, set `force` to `true` and rerun those identifiers to obtain a fresh check.

***

### ❓ Frequently Asked Questions About Google Shopping Scraping

**What does this Google Shopping scraper actually return?**
One record per product identifier you submit, containing the identifiers, the country code, outcome flags, product attributes, the full `offers` array, the offer count, the lowest and highest total prices, and freshness timestamps.

**What format should the `products` input use?**
Plain text with one identifier per line. The actor splits on newlines and trims each entry, and blank lines are ignored, so pasting a column straight out of a spreadsheet works without further formatting.

**Which countries can I target?**
Any country code accepted by Google Shopping's `gl` parameter. The default is `NL`. Whatever you supply is lower-cased and stored on each record so multi-market datasets remain unambiguous.

**Does the actor need a Google API key?**
No. It queries Google Shopping's public interface directly, so there is no API key to obtain and no developer quota attached to your account.

**What is the difference between `found` and `no_offers_found`?**
`found` tells you whether the product resolved at all. `no_offers_found` tells you whether it resolved but had no seller listings. A record can be found and still have no offers, which is a meaningful market signal rather than a failure.

**How do I get per-seller prices rather than just the summary?**
Read the `offers` array. Each entry contains `sellerName`, `sellerReference`, `price`, `shippingPrice`, `totalPrice`, `condition` and `availability`.

**Does `lowest_total_price` include shipping?**
It is derived from the `totalPrice` values in the offers array, which combine item price and shipping where a shipping price is stated. Where a merchant does not state shipping, `shippingPrice` is null and the total equals the item price.

**What does `age_hours` mean?**
How old the returned data is, in hours, at the time the record was produced. Use it together with `checked_at` and `fetched_at` to decide whether a value meets your freshness requirements.

**When should I set `force` to true?**
When you need certainty that the lookup was performed fresh rather than returning a previously stored outcome — typically during an investigation, or when `age_hours` on an earlier record exceeded your threshold.

**Can I scrape Google Shopping by keyword instead of by identifier?**
This actor is identifier-driven. Its input is a list of product codes, which is what makes each output row joinable to a catalogue record. Keyword search is not part of its input schema.

**Can I export the results to Excel or Google Sheets?**
Yes. Apify datasets export to CSV, XLSX, JSON and XML from the Console, and the dataset API endpoint can be consumed directly by Google Sheets or any BI tool that reads CSV or JSON over HTTP.

**How do I schedule recurring Google Shopping price checks?**
Create an Apify Schedule pointing at this actor with your saved input. Keep the `products` list and `country` value identical between runs so the resulting snapshots form a comparable time series.

**Is scraping Google Shopping legal?**
The actor reads publicly visible Google Shopping results. Public data collection is broadly permissible in many jurisdictions, but you remain responsible for complying with Google's Terms of Service and any laws or contracts that apply to you. Take legal advice before redistributing collected data commercially.

**Are the fields ever null?**
Yes. Fields that Google does not supply for a given product — commonly `sku`, `brand`, `thumbnail` or `currency` on unresolved lookups — come back as `null` rather than being omitted, so the record shape stays consistent across every row.

**How do I connect the output to my own systems?**
Use the dataset API, an Apify webhook that fires on run completion, or one of the no-code integrations such as Zapier, Make, Google Sheets or Slack.

***

### 🆘 Support & Feedback

Spotted a problem with the Google Shopping scraper, or a field that is not behaving as documented? Report it on the **Issues** tab of this actor so it can be tracked and fixed in the open.

If you need a custom build — additional offer attributes, a different input format, keyword-driven lookups, or an output shape tailored to your warehouse — email **scraperhubapi@gmail.com** with a description of your use case.

If this actor is useful to you, a rating and a short review on the actor page genuinely helps other pricing and ecommerce teams find it, and it guides what gets built next.

***

### ⚖️ Disclaimer

This Google Shopping scraper accesses only publicly visible product and offer information. It does not log in to any account, bypass authentication, or retrieve data that is not already displayed to ordinary visitors.

Responsibility for how the collected data is used rests with you. That includes observing Google's Terms of Service, respecting applicable copyright and database rights, and complying with any competition or consumer-protection rules that govern price monitoring in the markets you operate in.

The fields returned describe products, merchants and prices rather than individuals. Should any record you collect nonetheless contain personal data — a sole trader's name appearing as a seller, for example — you act as the data controller for that record and must comply with the GDPR, the UK GDPR, the CCPA or whichever privacy regime applies, including lawful basis, retention limits and data subject rights.

This actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Google LLC. If you believe data collected through this actor should be removed, write to **scraperhubapi@gmail.com** with the specifics and the request will be handled promptly.

# Actor input Schema

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

Enter one product per line. Can be EAN, UPC, or search keywords.

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

2-letter country code (e.g., NL, US, GB).

## `force` (type: `boolean`):

If true, bypass cache and force a new scrape.

## Actor input object example

```json
{
  "products": "8720648364181\n1234567890123",
  "country": "NL",
  "force": false
}
```

# Actor output Schema

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

Records scraped by Google Shopping Scraper - Extra Offers, stored in the run's default dataset.

# 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 = {
    "products": `8720648364181
1234567890123`,
    "country": "NL"
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapers-hub/google-shopping-scraper-extra-offers").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 = {
    "products": """8720648364181
1234567890123""",
    "country": "NL",
}

# Run the Actor and wait for it to finish
run = client.actor("scrapers-hub/google-shopping-scraper-extra-offers").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 '{
  "products": "8720648364181\\n1234567890123",
  "country": "NL"
}' |
apify call scrapers-hub/google-shopping-scraper-extra-offers --silent --output-dataset

```

## MCP server setup

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

```

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/iFNODGUSVShi7AfCW/builds/5s6ghUAljQ5wDslXY/openapi.json
