# Multi-Retailer MAP & Price-Violation Monitor (`seibs.co/map-price-monitor`) Actor

Monitor product prices across Target, Walmart, Best Buy and Newegg, then flag MAP (minimum advertised price) violations and unauthorized resellers. Cross-retailer SKU matching by UPC/MPN, graded violation severity, daily monitor mode. For brands and MAP enforcement.

- **URL**: https://apify.com/seibs.co/map-price-monitor.md
- **Developed by:** [Seibs.co](https://apify.com/seibs.co) (community)
- **Categories:** E-commerce, Business, AI
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 listing records

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

## Multi-Retailer MAP & Price-Violation Monitor

Monitor a brand's products across multiple retailers, match each SKU across their
disparate catalogs, and detect **MAP (Minimum Advertised Price) violations** and
**unauthorized resellers** - from logged-out public product pages.

Single-retailer price scrapers are a commodity (priced to the floor). The value
here is the layer enterprise MAP tools gate behind quote-based pricing: **"here
are my SKUs - flag everywhere they're advertised below MAP, and by whom."** That
means two things this actor owns end to end:

1. **Cross-retailer SKU matching + normalization** - one product collapsed across
   retailers by UPC / MPN / fuzzy name, with one normalized price/seller schema.
2. **MAP violation detection** - advertised price below the floor, graded by
   severity, cross-referenced against your authorized-seller list.

> **Responsible use (read this).** Retailer Terms of Service treat scraping as a
> gray area, so this actor is deliberately conservative: **logged-out public
> product pages only**, polite rate limits, capped result counts, **no account
> creation, no login, no CAPTCHA bypass**. A blocked retailer **fails soft** with
> a documented record - we never fabricate a price. Use within each retailer's
> terms and your own legal counsel's guidance. You are responsible for how you
> use the output.

***

### Modes

| Mode | What it returns | Charges |
|---|---|---|
| `price_scan` | Normalized public price rows per product across retailers (the flat listings). | `listing_record` |
| `cross_retailer_match` | Each product collapsed into one cross-retailer view: which retailers carry it, price spread (min/median/max), lowest offer. | `listing_record` + `sku_match` |
| **`map_monitor`** (flagship) | Everything above **+ MAP-violation detection** with graded severity, seller identity, and unauthorized-seller flags, plus a violation summary. | + `map_violation_flag` per violation |
| `seller_audit` | Offers grouped by seller, with **unauthorized third-party resellers** flagged and a below-MAP cross-reference. | `listing_record` + `map_violation_flag` |

***

### Retailer coverage (honest labelling)

| Retailer | Code | Access | Anti-bot | Coverage |
|---|---|---|---|---|
| Target | `target` | RedSky public web JSON | moderate | **full** |
| Best Buy | `bestbuy` | search HTML | high (Akamai) | **full** |
| Newegg | `newegg` | search HTML | moderate | **full** |
| Walmart | `walmart` | `__NEXT_DATA__` JSON (browser tier) | high (PerimeterX) | **full** |
| The Home Depot | `homedepot` | GraphQL via browser | high | catalog\* |
| Lowe's | `lowes` | SPA state blob | high | catalog\* |
| Costco | `costco` | search HTML | high | catalog\* |
| B\&H Photo | `bhphoto` | search HTML | moderate | catalog\* |
| Wayfair | `wayfair` | SPA | high | catalog\* |
| Macy's | `macys` | SPA | high | catalog\* |
| Micro Center | `microcenter` | product grid HTML | low | catalog\* |

`*` **catalog** = registered with the correct public surface, access method,
anti-bot tier and proxy, and wired into the escalation pipeline, but a
retailer-specific parser is pending. These emit a documented `retailer_pending`
note rather than fabricated data. Upgrading one to **full** is a single parser -
the orchestrator, matcher, violation engine, and monitor layers are
retailer-agnostic. The live `access_notes` record in every run reports the full
matrix and which tier each fetch used.

#### Anti-bot escalation

On a block, the fetch ladder escalates instead of giving up:

```
httpx (datacenter)  ->  curl_cffi Chrome-TLS impersonation (residential)
                    ->  patchright stealth browser (residential)  ->  fail-soft
```

`use_browser_fallback` (default on) enables the curl\_cffi + browser tiers; Walmart
and the WAF-fronted retailers need them. The optional CAPTCHA solver is **off by
default and never invoked by the shipped recipes** - a CAPTCHA wall fails soft.
Set `browser_cdp_url` to point the browser tier at a warm anti-detect browser for
the toughest managed-challenge retailers.

***

### Input

```jsonc
{
  "mode": "map_monitor",
  "products": [
    {
      "label": "Sony WH-1000XM5 Headphones",
      "brand": "Sony",
      "model": "WH-1000XM5",
      "upc": "027242923058",          // best: exact cross-retailer match
      "mpn": "WH1000XM5/B",
      "query": "Sony WH-1000XM5",      // search string (defaults to label)
      "map_price": 399.99,             // authoritative MAP floor
      "authorized_sellers": ["Best Buy", "Crutchfield"]
    }
  ],
  "retailers": ["target", "bestbuy", "newegg", "walmart"],
  "default_map_price": null,           // fallback floor for products with no map_price
  "infer_map": false,                  // infer an ADVISORY MAP proxy when none supplied
  "authorized_sellers": ["Best Buy"],  // run-wide list; per-product overrides it
  "max_results_per_retailer": 24,
  "use_browser_fallback": true
}
```

Quick path: skip `products` and pass `search_terms: ["Sony WH-1000XM5", "Bose QC Ultra"]`
to monitor by name. Supply a **UPC or MPN** for exact matching; supply `map_price`
for authoritative violation flags.

**MAP threshold priority:** per-product `map_price` -> run-wide `default_map_price`
-> (if `infer_map`) an inferred proxy from the observed cross-retailer price
distribution (manufacturer list/MSRP anchor). **Inferred thresholds are advisory**
and clearly labelled (`map_source: "inferred_*"` + a `_disclaimer`); they are not
your contractual MAP.

***

### Output

One dataset; `record_type` distinguishes rows: `listing`, `sku_match`,
`seller_audit`, `violation_summary`, `access_notes`, `fetch_error`,
`retailer_pending`, `no_match`.

A `listing` in `map_monitor` mode:

```jsonc
{
  "record_type": "listing",
  "product_query": "Sony WH-1000XM5 Headphones",
  "matched": true, "match_method": "upc", "match_confidence": 1.0,
  "retailer": "walmart", "seller": "DealZone Electronics", "seller_type": "third_party",
  "title": "Sony WH-1000XM5 Wireless Noise Cancelling Headphones - Black",
  "upc": "027242923058", "mpn": "WH1000XM5B",
  "price": 348.0, "list_price": 399.99, "availability": "in_stock",
  "map_threshold": 399.99, "map_source": "user",
  "map_violation": true, "violation_amount": 51.99, "violation_pct": 0.13,
  "violation_severity": "moderate",
  "unauthorized_seller": true, "enforcement_priority": true,
  "url": "https://www.walmart.com/ip/1872934501", "via": "browser"
}
```

Dataset views: **overview** (AI-agent / dashboard skim), **violations** (the
enforcement worklist - below-MAP listings only), **detailed** (every field).

#### Severity grading

`violation_pct` = how far below MAP the price is. `minor` <=5%, `moderate` 5-15%,
`severe` >15%. A price exactly at MAP is compliant (`at_map: true`).
`enforcement_priority: true` marks a below-MAP price from an **unauthorized**
seller - the top target.

***

### Pricing (pay-per-event)

| Event | Price | When |
|---|---:|---|
| `listing_record` | $0.004 | Per normalized listing matched to your SKU. |
| `sku_match` | $0.008 | Per product collapsed across retailers (non-`price_scan` modes). |
| `map_violation_flag` | $0.012 | Per listing flagged below MAP (the premium signal). |
| `scheduled_delta_run` | $0.050 | Per scheduled monitor run (new-violations digest). |

A `_RunBudget` guard caps runaway compute and a hard record cap protects against
unbounded cost; over-large inputs are rejected pre-flight and routed to a labelled
demo run rather than failing.

***

### Monitor mode (ongoing violation alerts)

Save your config as a task and **schedule it** (Apify Console -> Schedules). On a
scheduled run the actor computes the delta vs the prior run, emits a
`monitor_digest` of **new** violations / price drops, optionally POSTs it to a
Slack `monitor_webhook_url`, and charges one `scheduled_delta_run`. This is the
recurring, compliance-driven workflow brands actually pay for.

***

### Running it

In the Apify Console: pick a mode, add your products + retailers, Start. Or via API:

```bash
apify call YOUR_USERNAME/map-price-monitor --input '{
  "mode": "map_monitor",
  "search_terms": ["Sony WH-1000XM5"],
  "retailers": ["target", "bestbuy", "newegg"],
  "default_map_price": 399.99
}'
```

AI agents: use the paired **`mcp-map-price-monitor`** MCP server
(`scan_prices`, `check_map_violations`, `match_across_retailers`, `audit_sellers`)

- x402 (USDC on Base) and Skyfire ready.

# Actor input Schema

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

price\_scan = normalized public price rows per product. cross\_retailer\_match = collapse each product into one cross-retailer view (price spread, lowest offer). map\_monitor = + MAP-violation detection with graded severity (flagship). seller\_audit = group offers by seller and flag unauthorized resellers.

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

Your brand's products. Each item: { "label": "Sony WH-1000XM5", "upc": "027242923058", "mpn": "WH1000XM5/B", "brand": "Sony", "model": "WH-1000XM5", "query": "Sony WH-1000XM5", "map\_price": 399.99, "authorized\_sellers": \["Best Buy", "Crutchfield"] }. Supply UPC or MPN for exact cross-retailer matching; map\_price for authoritative violation flags. Hard cap of 100.

## `search_terms` (type: `array`):

Quick alternative to 'products' when you only have product names. Each string becomes a product searched by name across the selected retailers. Hard cap of 100.

## `retailers` (type: `array`):

Which retailers to query. Fully-parsed: target, bestbuy, newegg, walmart. Catalog-registered (parser pending, documented): homedepot, lowes, costco, bhphoto, wayfair, macys, microcenter. Leave empty for the default set (target, bestbuy, newegg, walmart), or pass \['ALL'].

## `default_map_price` (type: `integer`):

A fallback MAP threshold (USD) applied to every product that has no map\_price of its own. Used in map\_monitor / seller\_audit modes. Leave blank to rely on per-product map\_price or inference.

## `infer_map` (type: `boolean`):

When no map\_price (per-product or default) is given, infer an ADVISORY MAP proxy from observed cross-retailer prices (manufacturer list/MSRP anchor). Inferred thresholds are clearly labelled and are not the brand's contractual MAP. Off by default.

## `authorized_sellers` (type: `array`):

Run-wide list of seller names authorized to sell your brand (e.g. \['Best Buy', 'Crutchfield', 'B\&H']). Any third-party seller not on this list is flagged unauthorized in seller\_audit / map\_monitor. Per-product authorized\_sellers override this. Hard cap of 300.

## `only_violations` (type: `boolean`):

In map\_monitor mode, push only the listings that violate MAP (plus the rollups + summary), instead of every matched listing. Off by default.

## `max_results_per_retailer` (type: `integer`):

Hard cap on listings considered per retailer per product (before matching filters them to your SKU). Default 24.

## `name_match_threshold` (type: `string`):

Acceptance threshold (0-1) for fuzzy name matching when no UPC/MPN is available. Default 0.82. Raise to reduce false matches, lower to catch more variants.

## `target_api_key` (type: `string`):

Override the public anonymous Target RedSky web key if the shipped default rotates. Leave blank to use the default. This is the same anonymous key target.com's own logged-out frontend uses.

## `use_apify_proxy` (type: `boolean`):

Route retailer requests through Apify Proxy. DATACENTER for the cheap httpx pass, RESIDENTIAL for the curl\_cffi / browser escalation legs.

## `apify_proxy_groups` (type: `array`):

Override the DATACENTER proxy groups for the httpx tier. The escalation tiers always use RESIDENTIAL when browser fallback is on.

## `use_browser_fallback` (type: `boolean`):

On a block, escalate httpx -> curl\_cffi TLS impersonation (residential) -> patchright browser (residential). Required for Walmart and the WAF-fronted retailers. Off = httpx only (fewer retailers succeed).

## `browser_cdp_url` (type: `string`):

Connect the browser tier to a warm anti-detect browser over CDP (inherits its session + IP) to clear managed bot walls. Leave blank to launch a fresh patchright browser.

## `concurrency` (type: `integer`):

Parallel retailer requests. Kept low (default 4) to stay polite. Max 8.

## `monitor_webhook_url` (type: `string`):

Optional. On a scheduled (monitor-mode) run, POST the new-violations digest to this Slack incoming-webhook URL.

## Actor input object example

```json
{
  "mode": "map_monitor",
  "products": [
    {
      "label": "Sony WH-1000XM5 Headphones",
      "brand": "Sony",
      "model": "WH-1000XM5",
      "query": "Sony WH-1000XM5",
      "map_price": 399.99
    }
  ],
  "search_terms": [],
  "retailers": [
    "target",
    "bestbuy",
    "newegg"
  ],
  "infer_map": false,
  "authorized_sellers": [],
  "only_violations": false,
  "max_results_per_retailer": 12,
  "name_match_threshold": "0.82",
  "target_api_key": "",
  "use_apify_proxy": true,
  "apify_proxy_groups": [
    "DATACENTER"
  ],
  "use_browser_fallback": true,
  "browser_cdp_url": "",
  "concurrency": 4,
  "monitor_webhook_url": ""
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

Narrow, token-efficient slice of every record. Consumer: LLM agents (Claude, GPT, LangChain tools), MCP hosts, MAP dashboards. Fields: product, retailer, seller, price, MAP threshold, violation flag + severity, unauthorized-seller flag, URL.

## `datasetItemsViolations` (type: `string`):

Only the listings flagged below MAP, with amount/percentage/severity, seller identity, and the unauthorized + enforcement-priority flags. Consumer: brand MAP-enforcement teams, repricers, Zapier/Make alerts.

## `datasetItemsDetailed` (type: `string`):

All fields for every record. Consumer: humans browsing in the Apify UI, RAG ingest pipelines, full backups.

## `datasetItemsMcp` (type: `string`):

First 50 overview records as a clean JSON array. Wrap on the agent side in an MCP tool-call response envelope, e.g. `{ "ok": true, "data": <this array>, "meta": { "actor": "map-price-monitor", "count": <len>, "view": "overview" } }`. Consumer: MCP servers, Claude Desktop, Cursor, OpenAI Assistants tool calls.

## `datasetItemsCsv` (type: `string`):

Spreadsheet-friendly export of the overview view. Consumer: humans, brand-ops teams, Excel / Google Sheets users.

# 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": "map_monitor",
    "products": [
        {
            "label": "Sony WH-1000XM5 Headphones",
            "brand": "Sony",
            "model": "WH-1000XM5",
            "query": "Sony WH-1000XM5",
            "map_price": 399.99
        }
    ],
    "retailers": [
        "target",
        "bestbuy",
        "newegg"
    ],
    "max_results_per_retailer": 12
};

// Run the Actor and wait for it to finish
const run = await client.actor("seibs.co/map-price-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 = {
    "mode": "map_monitor",
    "products": [{
            "label": "Sony WH-1000XM5 Headphones",
            "brand": "Sony",
            "model": "WH-1000XM5",
            "query": "Sony WH-1000XM5",
            "map_price": 399.99,
        }],
    "retailers": [
        "target",
        "bestbuy",
        "newegg",
    ],
    "max_results_per_retailer": 12,
}

# Run the Actor and wait for it to finish
run = client.actor("seibs.co/map-price-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 '{
  "mode": "map_monitor",
  "products": [
    {
      "label": "Sony WH-1000XM5 Headphones",
      "brand": "Sony",
      "model": "WH-1000XM5",
      "query": "Sony WH-1000XM5",
      "map_price": 399.99
    }
  ],
  "retailers": [
    "target",
    "bestbuy",
    "newegg"
  ],
  "max_results_per_retailer": 12
}' |
apify call seibs.co/map-price-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,seibs.co/map-price-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/80bNX8OB9QfehT5Ok/builds/dgI7B3Vts4NkkSylR/openapi.json
