# Google Shopping Price Tracker & Seller Monitor (`herazur/google-shopping-price-seller-monitor`) Actor

Track Google Shopping prices, sellers, rankings, MAP violations, and unauthorized merchants across countries. Monitor products on a schedule and detect price, seller, and ranking changes automatically.

- **URL**: https://apify.com/herazur/google-shopping-price-seller-monitor.md
- **Developed by:** [Furkan Toluç](https://apify.com/herazur) (community)
- **Categories:** E-commerce, SEO tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 google shopping offer delivereds

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?

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 Price Monitor & Seller Tracker — MAP Alerts

Turn Google Shopping results into a recurring price and seller monitoring feed—not another generic scraper.

```text
250 products monitored
3 new sellers detected
2 unauthorized sellers found
4 MAP violations
17 price changes
6 ranking changes
```

Track exact products by model, SKU, GTIN, or high-specificity keyword across countries. The Actor normalizes merchants, preserves stable offer IDs, compares scheduled runs, and reports meaningful price, seller, MAP, and rank changes in a stable Dataset schema.

### What it does

```text
Product/SKU query
→ Google Shopping offers
→ deterministic product matching
→ merchant normalization
→ persistent historical comparison
→ actionable changes
```

Every candidate is classified as `EXACT`, `LIKELY`, `AMBIGUOUS`, or `REJECTED`. High-risk alerts such as MAP violations and unauthorized-seller events require an `EXACT` match with at least 0.95 confidence.

The monitor detects:

- `NEW_SELLER` and `REMOVED_SELLER`
- `UNAUTHORIZED_SELLER`
- `PRICE_DROP` and `PRICE_INCREASE`
- `NEW_LOWEST_PRICE`
- `MAP_VIOLATION` and `MAP_VIOLATION_RESOLVED`
- `RANK_GAIN` and `RANK_LOSS`
- `OFFER_DISAPPEARED` and `OFFER_REAPPEARED`

This makes the Actor useful as a Google Shopping Price Monitor, Google Shopping Price Tracker, Competitor Price Monitoring feed, MAP Monitoring tool, Unauthorized Seller Detection workflow, Google Shopping Seller Tracker, and Google Shopping Rank Tracker.

### Who it is for

- Brands enforcing advertised-price policies
- Ecommerce and marketplace teams tracking competitor prices
- Agencies monitoring seller and ranking changes across client catalogs
- Distributors auditing authorized and unauthorized sellers
- Automation builders using n8n, Make, Zapier, Airtable, Google Sheets, HubSpot, or custom scripts

### Quick start

```json
{
  "products": [
    {
      "inputId": "sony-xm5-black",
      "query": "Sony WH-1000XM5 Black",
      "brand": "Sony",
      "model": "WH-1000XM5",
      "gtin": null,
      "mapPrice": 349.99,
      "authorizedSellers": ["Amazon", "Best Buy", "Sony"],
      "condition": "NEW"
    }
  ],
  "markets": [
    { "country": "us", "language": "en", "currency": "USD" }
  ],
  "mode": "MONITOR"
}
```

Use exact model numbers and include color or size in the query when variants matter. Keep `inputId`, market settings, and `stateStoreName` stable between scheduled runs.

### SNAPSHOT and MONITOR

`SNAPSHOT` collects and normalizes the current Google Shopping observations. It does not read or change monitoring history.

`MONITOR` loads the prior state from the named Apify key-value store, compares current observations in O(n) maps, emits changes, and saves the new state. The first MONITOR run establishes the baseline. Current high-confidence MAP and authorization conditions are still visible on the baseline; historical deltas begin with the next successful run.

If a request fails or returns an unconfirmed empty parser result, the prior state is preserved. This prevents a temporary block or Google markup change from generating a wave of false seller-disappearance alerts.

### Product matching

Matching is deterministic and does not use OpenAI, Claude, Gemini, or another external AI API. Signals include:

- normalized brand and exact model number
- GTIN/EAN when exposed
- color and size tokens inferred from the query
- conflicting model and variant detection
- product condition
- accessory and bundle terms, including common localized terms
- normalized query-token overlap

`REJECTED` and `AMBIGUOUS` candidates remain available for audit but are not billed and never generate MAP or unauthorized-seller alerts. `LIKELY` offers can be delivered as useful observations but do not trigger risky business alerts.

### Merchant normalization and authorized sellers

The Actor returns:

- `merchant`
- `merchantCanonical`
- `merchantDomain`
- `merchantId`
- `sellerAuthorization`: `AUTHORIZED`, `UNAUTHORIZED`, or `UNKNOWN`

An exposed merchant or product domain is the strongest signal. Known aliases such as Amazon/Amazon.com and Best Buy/BestBuy normalize conservatively. Uncertain merchant identities remain `UNKNOWN` instead of being labeled unauthorized.

### MAP monitoring

Set `mapPrice` in the market's configured currency. For a new, high-confidence exact match:

```text
MAP price:             $349.99
Observed price:        $319.99
Violation amount:       $30.00
Violation percentage:     8.57%
```

The output includes `mapViolation`, `mapViolationAmount`, and `mapViolationPercentage`. Used/refurbished, ambiguous, likely, and rejected results do not produce MAP alerts.

### Dataset output

The default Dataset primarily contains normalized observations. Every row uses `schemaVersion: "1.0"` and consistently supplies optional fields as `null` or `[]`.

`recordType` distinguishes:

- `OFFER`: a currently visible candidate
- `CHANGE`: a disappeared/removed offer transition
- `ERROR`: a product-market failure that did not stop the rest of the run

Important fields include stable IDs, input/market identity, `price`/`currentPrice`, `previousPrice`, merchant identity, match evidence, authorization, MAP calculations, `position`/`currentPosition`, `previousPosition`, timestamps, and `changeTypes`. The run summary is also available from the default key-value store record `OUTPUT` (and alias `SUMMARY`); structured errors are stored under `ERRORS`.

### Scheduled monitoring

1. Run once in `MONITOR` mode to establish the baseline.
2. Save the input as an Apify Task.
3. Add a daily, twice-daily, or weekly Apify Schedule.
4. Trigger a webhook or integration after successful runs.
5. Filter Dataset rows where `changeTypes` is non-empty, `mapViolation` is `true`, or `sellerAuthorization` is `UNAUTHORIZED`.

Do not change the history store name between scheduled runs. Separate stores can be used to isolate customers, brands, or environments.

### API usage

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/herazur~google-shopping-price-seller-monitor/runs?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d @examples/input.json
```

After the run finishes, read:

- normalized observations from the default Dataset
- summary from key-value store record `OUTPUT`
- partial-run errors from key-value store record `ERRORS`

### Make, n8n, Zapier, and Sheets

- **Make/Zapier:** Run Actor → wait for completion → get Dataset items → filter on `changeTypes`.
- **n8n:** Use the Apify node or HTTP Request node, then branch on MAP, price, seller, or rank events.
- **Google Sheets/Airtable:** Export flat Dataset fields; `inputId` provides a reliable join key to the source catalog.
- **HubSpot/custom scripts:** Use webhooks and the Dataset API to create tickets, alerts, or account-level monitoring records.

### Pricing

Pay per event:

```text
shopping_offer_delivered: $0.004 per successfully delivered usable offer
                         = $4.00 per 1,000 offers
```

There is no charge for invalid input, request/parser failure, empty output, malformed offers, `AMBIGUOUS`/`REJECTED` matches, disappearance/error rows, retries, or duplicate billable observations. Change detection is included in the observation price.

The Actor writes a durable pending billing marker before each PPE delivery. If a run is interrupted during an ambiguous network outcome, it favors under-billing over risking a duplicate charge.

### Reliability and performance

- Apify Google SERP Proxy with HTTP extraction; no browser in production
- country-specific proxy sessions plus currency-mismatch rejection for market integrity
- bounded concurrency and exponential retry backoff
- configurable request timeout and offer limit
- one product-market failure does not fail other work
- deterministic request and offer deduplication
- O(n) historical comparison
- named persistent state partitioned by product and market
- graceful SIGTERM/SIGINT handling
- spending-limit detection from Apify PPE charge results

### Limitations

- Google Shopping markup and product grouping change without notice. Structured errors and state-preservation guards reduce false alerts, but parser maintenance is an operational requirement.
- Google can aggregate additional sellers behind “& more.” The Actor reports seller offers exposed in the Shopping result markup and does not fabricate hidden sellers.
- Direct merchant/product URLs, GTINs, images, shipping, ratings, and offer IDs are returned only when Google exposes them; otherwise fields are `null`.
- Google product/session IDs can be volatile. Stable monitoring IDs intentionally rely on input, market, product identity, and normalized merchant identity instead of price or Google session IDs.
- Rankings can legitimately vary by location, time, personalization, inventory, and experiments. The Actor disables personalized search where possible but cannot make Google rankings globally deterministic.
- Title-only matching cannot prove catalog identity in every category. Supply model numbers or GTINs, review `matchReasons`, and reserve business enforcement for high-confidence exact results.

### Responsible usage

Google's current terms and robots instructions create material platform/compliance risk for automated search access. Apify provides a purpose-built Google SERP Proxy, but that does not eliminate your responsibility to assess Google terms, applicable laws, contract obligations, data rights, MAP-policy enforceability, and acceptable request rates. This Actor is a data-monitoring tool, not legal advice or an automatic enforcement system.

### Development

```bash
npm install
npm run validate
```

Local input lives at `storage/key_value_stores/default/INPUT.json`. Production runs should keep Google SERP Proxy enabled.

# Actor input Schema

## `products` (type: `array`):

Add products by SKU/model/GTIN-focused query. A stable inputId keeps each product's history separate.

## `markets` (type: `array`):

Country, Google interface language, and expected ISO currency for each market.

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

SNAPSHOT returns current observations. MONITOR also loads and updates persistent history.

## `maxConcurrency` (type: `integer`):

Maximum simultaneous Shopping requests.

## `maxRequestRetries` (type: `integer`):

Retries after a request, rate-limit, timeout, or traffic challenge failure.

## `requestTimeoutSecs` (type: `integer`):

Per-attempt timeout in seconds.

## `maxOffersPerQuery` (type: `integer`):

Maximum Shopping candidates parsed before product matching and merchant deduplication.

## `stateStoreName` (type: `string`):

Named key-value store used across MONITOR runs. Keep this stable for continuous history.

## `proxyConfiguration` (type: `object`):

Google SERP Proxy is enabled in production.

## Actor input object example

```json
{
  "products": [
    {
      "inputId": "sony-xm5-black",
      "query": "Sony WH-1000XM5 Black",
      "brand": "Sony",
      "model": "WH-1000XM5",
      "gtin": null,
      "mapPrice": 349.99,
      "authorizedSellers": [
        "Amazon",
        "Best Buy",
        "Sony"
      ],
      "condition": "NEW"
    }
  ],
  "markets": [
    {
      "country": "us",
      "language": "en",
      "currency": "USD"
    }
  ],
  "mode": "MONITOR",
  "maxConcurrency": 5,
  "maxRequestRetries": 3,
  "requestTimeoutSecs": 30,
  "maxOffersPerQuery": 100,
  "stateStoreName": "google-shopping-price-monitor-state",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `observations` (type: `string`):

Default Dataset containing schemaVersion 1.0 rows.

## `summary` (type: `string`):

Machine-readable processing and alert counts.

## `errors` (type: `string`):

Failures that did not stop the remaining product-market jobs.

# 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": [
        {
            "inputId": "sony-xm5-black",
            "query": "Sony WH-1000XM5 Black",
            "brand": "Sony",
            "model": "WH-1000XM5",
            "gtin": null,
            "mapPrice": 349.99,
            "authorizedSellers": [
                "Amazon",
                "Best Buy",
                "Sony"
            ],
            "condition": "NEW"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("herazur/google-shopping-price-seller-monitor").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": [{
            "inputId": "sony-xm5-black",
            "query": "Sony WH-1000XM5 Black",
            "brand": "Sony",
            "model": "WH-1000XM5",
            "gtin": None,
            "mapPrice": 349.99,
            "authorizedSellers": [
                "Amazon",
                "Best Buy",
                "Sony",
            ],
            "condition": "NEW",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("herazur/google-shopping-price-seller-monitor").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": [
    {
      "inputId": "sony-xm5-black",
      "query": "Sony WH-1000XM5 Black",
      "brand": "Sony",
      "model": "WH-1000XM5",
      "gtin": null,
      "mapPrice": 349.99,
      "authorizedSellers": [
        "Amazon",
        "Best Buy",
        "Sony"
      ],
      "condition": "NEW"
    }
  ]
}' |
apify call herazur/google-shopping-price-seller-monitor --silent --output-dataset

```

## MCP server setup

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

```

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/c2uVYDvBnaXZKfLTe/builds/6RazCp88inaoVeBxa/openapi.json
