# Competitor Price Monitor & Repricing for Shops (`prevailing_glow/competitor-price-monitor`) Actor

Track competitor prices on any shop URL (Shopify, WooCommerce, JSON-LD) vs your price and cost. Get safe repricing suggestions; optional Shopify/Woo push.

- **URL**: https://apify.com/prevailing_glow/competitor-price-monitor.md
- **Developed by:** [Dave West](https://apify.com/prevailing_glow) (community)
- **Categories:** E-commerce, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 product price checkeds

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

## Competitor Price Monitor & Repricing for Shops

**Competitor price monitoring for your own catalog**: paste your products with your price (and cost), add the
competitor product URLs from **any shop** (Shopify, WooCommerce, Magento, custom), and get one row per product with
the **lowest competitor price, your price gap, change since the last run** and a **safe repricing suggestion** that
respects your **floor price, minimum margin and maximum change**. Optionally push the new prices to **Shopify**,
**WooCommerce** or any platform through a **webhook**.

Built for small and mid-size web shops, marketplace sellers and e-commerce agencies who want a daily **price tracker**
without a $100/month repricing SaaS. You **only pay for pages where a price was found**: blocked pages, pages without a
price, summaries and suggestions are free.

- **Any product URL**: prices are read from Shopify's public product JSON, schema.org JSON-LD (Product / Offer /
  AggregateOffer / ProductGroup variants), microdata, OpenGraph / product meta tags and WooCommerce price markup.
- **Your price vs theirs**: gap in money and percent, cheapest / equal / above-lowest position, min / average / max.
- **Repricing rules**: match the lowest, undercut by % or amount, or stay a % above. Guards: floor price,
  minimum margin on cost, maximum change per run, "never raise", ignore out-of-stock and other-currency offers.
- **Price history**: every scheduled run compares with the previous one (price drop, price increase, back in stock,
  out of stock) using a named key-value store in your account.
- **Three modes**: *Monitor only*, *Suggest* (you approve each price) and *Automatic* (rules decide; shop push
  only when you switch it on).
- **EU-ready**: `1.299,00 €`, `12,-`, `1 299,00 kr`, `CHF 1'299.90`, and `1,299.00` all parse; currency is
  detected and never mixed.
- **Polite and legal by design**: real user agent, robots.txt respected, one request at a time per shop, timeouts.
  The Actor **never bypasses captchas or bot protection**: blocked pages are reported as `blocked` and not charged.

### How it works

1. Add your products (in the input, or as a JSON / CSV feed URL, e.g. a Google Sheet published as CSV).
2. For each product add one or more competitor product page URLs.
3. Run it once, check the **Overview** table, then **schedule it daily** (Console -> Schedules).
4. Read the suggestions in the **Repricing** view, or let *Automatic* mode push approved rules to your shop.

```
Your catalog ──► competitor pages (HTTP, polite) ──► price + currency + stock
                                                        │
       your price / cost / floor ──► rules + guards ──► suggested price ──► (optional) Shopify / WooCommerce / webhook
```

### Input

| Field | What it does | Default |
|---|---|---|
| `products` | Your products: `sku`, `name`, `yourPrice`, `currency`, optional `costPrice`, `floorPrice`, `ean`, `yourUrl`, and `competitors` (URLs or `{name, url}`) | 3 demo products |
| `catalogUrl` | Public JSON or CSV feed with the same fields (see below) | - |
| `mode` | `monitor`, `suggest` or `auto` | `suggest` |
| `strategy` | `undercut_percent`, `undercut_amount`, `match_lowest`, `premium_percent` | `undercut_percent` |
| `undercutPercent` / `undercutAmount` / `premiumPercent` | Strategy parameters | 2 / 1 / 5 |
| `minMarginPercent` | Never below `cost / (1 - margin)`; 0 = never below cost | 0 |
| `floorPrice` | Never below this (a product's own `floorPrice` wins) | - |
| `maxChangePercent` | Max move from your current price per run | 15 |
| `allowPriceIncrease` | Suggest raising when competitors are more expensive | true |
| `ignoreOutOfStock` | Out-of-stock offers don't drive suggestions | true |
| `maxProducts` / `maxCompetitorsPerProduct` | Safety caps | 100 / 10 |
| `pushToShop` + `shopPlatform` | Write prices (Automatic mode only) | off |
| `shopifyDomain`, `shopifyAccessToken`🔒 | Shopify custom app (scope `write_products`) | - |
| `wooBaseUrl`, `wooConsumerKey`🔒, `wooConsumerSecret`🔒 | WooCommerce REST key (Read/Write) | - |
| `webhookUrl`🔒, `webhookSecret`🔒 | Any platform via Zapier / Make / n8n / your backend | - |
| `markets` | (Beta) competitor shops to search by EAN / name | - |
| `respectRobotsTxt`, `maxConcurrency`, `requestTimeoutSecs`, `proxyConfiguration`, `historyStoreName` | Advanced | true, 5, 20, off, `competitor-price-monitor-history` |

🔒 = secret field: stored encrypted by Apify, never written to the dataset, the logs or the key-value store (every
output is scrubbed for these values as an extra safety net).

#### Example input

```json
{
  "mode": "suggest",
  "strategy": "undercut_percent",
  "undercutPercent": 2,
  "minMarginPercent": 30,
  "maxChangePercent": 10,
  "products": [
    {
      "sku": "RUNNER-42",
      "name": "Trail runner",
      "yourPrice": 129.95,
      "currency": "EUR",
      "costPrice": 62,
      "ean": "8712345678906",
      "competitors": [
        { "name": "Shop A", "url": "https://shop-a.example/products/trail-runner" },
        { "name": "Shop B", "url": "https://shop-b.example/product/trail-runner/" }
      ]
    }
  ]
}
```

#### CSV feed

Comma, semicolon or tab separated; one row per competitor (rows with the same `sku` are grouped), or wide columns
`competitorUrl1, competitorUrl2, ...`. EU number formats are fine.

```csv
sku;name;yourPrice;currency;costPrice;competitorName;competitorUrl
RUNNER-42;Trail runner;129,95;EUR;62;Shop A;https://shop-a.example/products/trail-runner
RUNNER-42;Trail runner;129,95;EUR;62;Shop B;https://shop-b.example/product/trail-runner/
```

For shop push add `variantId` (Shopify variant ID) or `shopProductId` / `shopVariationId` (WooCommerce) columns.
Leave `yourPrice` empty and fill `yourUrl` to read your current price from your own product page.

### Output

One dataset row per product, with the competitor offers nested in `competitors`. Three table views:
**Overview** (one row per product), **Competitor offers** (one row per page) and **Repricing**.

```json
{
  "sku": "RUNNER-42",
  "name": "Trail runner",
  "yourPrice": 129.95,
  "currency": "EUR",
  "lowestCompetitor": "Shop B",
  "lowestPrice": 119,
  "lowestPriceChange": -5,
  "gap": 10.95,
  "gapPercent": 9.2,
  "position": "above_lowest",
  "comparableCount": 2,
  "changesSinceLastRun": 1,
  "suggestedPrice": 116.96,
  "decision": "review",
  "reason": "undercut_percent, lowest comparable: Shop B at 119 EUR: -12.99 (-10%); guards: max_change.",
  "guards": ["max_change"],
  "shopUpdate": { "sku": "RUNNER-42", "currentPrice": 129.95, "newPrice": 116.96, "currency": "EUR", "status": "needs_approval" },
  "shopResult": null,
  "chargedPages": 2,
  "competitors": [
    {
      "competitorName": "Shop B",
      "competitorUrl": "https://shop-b.example/product/trail-runner/",
      "competitorStatus": "ok",
      "competitorPrice": 119,
      "competitorCurrency": "EUR",
      "competitorAvailability": "InStock",
      "competitorSource": "json-ld",
      "competitorPreviousPrice": 124,
      "competitorPriceChange": -5,
      "competitorChangeType": "price_drop",
      "competitorGap": 10.95,
      "competitorUsed": true
    }
  ],
  "checkedAt": "2026-10-02T06:00:00.000Z"
}
```

`decision` is one of `monitor`, `review` (suggest mode), `apply` (automatic, not pushed), `pushed`, `push_failed`,
`hold` (already at the rule price), `no_data` (no comparable competitor price) or `no_your_price`.
`competitorStatus` is `ok`, `no_price`, `blocked`, `robots_disallowed`, `not_found`, `http_error` or `fetch_error`.
The run's **SUMMARY** record (key-value store) has counters, charges and warnings.

### Shop push (optional)

Only in **Automatic** mode with **Write new prices to my shop** on, and only when a rule changes the price:

- **Shopify**: Admin GraphQL API (`productVariantsBulkUpdate`) on `your-store.myshopify.com` with a custom-app token
  (`write_products`). Each product needs its `variantId`. The token is only ever sent to a `*.myshopify.com` domain.
- **WooCommerce**: REST API `PUT /wp-json/wc/v3/products/{id}` (or `/variations/{id}`) setting `regular_price`,
  over HTTPS with a Read/Write consumer key and secret. (If a product has an active `sale_price`, that one stays
  visible in your shop.)
- **Webhook**: a JSON POST per change (`sku, variantId, shopProductId, oldPrice, newPrice, currency, reason, runId`),
  optionally signed with `X-CPM-Signature: sha256=<HMAC-SHA256 of the body>`. Use it for UNAS, Shoprenter, OpenCart,
  Lightspeed, Magento, a Google Sheet, Slack, etc. via Zapier / Make / n8n.

Start with *Suggest* mode for a few days, check the suggestions, then switch on Automatic.

### Pricing

Pay per event, no subscription:

| Event | Price | When |
|---|---|---|
| `product-checked` | $0.004 ($4 per 1,000) | a competitor (or your own) product page where a price was found |
| `price-pushed` | $0.01 | a price your shop / webhook accepted |

Blocked, robots-disallowed and unpriced pages, summaries, suggestions and failed pushes are **free**.
Example: 200 products × 3 competitors, checked daily = 18,000 pages / month ≈ **$72 / month**; weekly ≈ $10.
Set **Maximum cost per run** in the run options: the Actor stops cleanly when it is reached (it reserves the budget
before fetching a page, so it never goes over).

### Limitations

- **No browser**: the Actor reads the HTML / JSON a shop sends. Prices that only appear after JavaScript runs
  (rare for shops; most server-render JSON-LD or meta tags) are reported as `no_price` (free). A headless Chrome
  fallback would need a ~1.5 GB image, 1-2 GB of memory and ~10× the compute per page, so it is deliberately left out.
- **Bot protection**: Cloudflare / DataDome / PerimeterX challenges and captchas are never bypassed; Amazon,
  bol.com, Zalando and other large marketplaces typically block automated requests and will show `blocked`.
- **Product matching**: you provide the competitor URLs. `markets` discovery is a beta helper that only keeps
  pages matching the EAN or most words of the name; shops whose robots.txt disallows search (e.g. all Shopify
  shops) are skipped.
- **Variants**: the price of the variant in the URL (`?variant=`) or the first in-stock variant is used.
- **Currencies**: offers in another currency are reported but not converted or used for suggestions. Shops with
  geo-pricing show the price for the Actor's server location (use the market URL, e.g. `/en-nl/products/...`).
- **Prices**: the advertised product price, without shipping, coupons or loyalty discounts. VAT handling follows
  what the shop displays.
- **History** is one record per store name; give parallel schedules different `historyStoreName`s.

### FAQ

**Is it legal to monitor competitor prices?** Reading publicly displayed prices is common practice; the Actor
respects robots.txt, identifies itself and does not bypass access controls. Check the terms of the sites you monitor.

**How often should I run it?** Daily is typical; hourly is possible for small catalogs (mind the cost).

**Can it run without competitor URLs?** Use `markets` (beta) with competitor home pages, or build URL lists with a
search / sitemap scraper first.

**Does it change my prices without asking?** Never by default. Prices are only written in Automatic mode with
the push switch on, within your floor, margin and max-change guards.

# Actor input Schema

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

One object per product of yours: <code>sku</code>, <code>name</code>, <code>yourPrice</code>, <code>currency</code>, optional <code>costPrice</code> / <code>floorPrice</code> / <code>ean</code>, and <code>competitors</code> (URLs, or <code>{"name", "url"}</code> objects pointing at competitor product pages). For shop push add <code>variantId</code> (Shopify) or <code>shopProductId</code> / <code>shopVariationId</code> (WooCommerce). Leave yourPrice empty and set <code>yourUrl</code> to read your price from your own product page.

## `catalogUrl` (type: `string`):

Optional public URL of a JSON array of products, or a CSV (comma or semicolon) with columns <code>sku, name, yourPrice, currency, costPrice, floorPrice, yourUrl, ean, competitorName, competitorUrl</code> (one row per competitor), or wide columns <code>competitorUrl1, competitorUrl2, ...</code>. A Google Sheet published as CSV works. Combined with the products above.

## `defaultCurrency` (type: `string`):

ISO code used for products without a currency, e.g. EUR, USD, GBP.

## `maxProducts` (type: `integer`):

Safety cap. Products beyond this number are ignored (with a warning).

## `maxCompetitorsPerProduct` (type: `integer`):

Extra competitor URLs beyond this number are ignored.

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

<b>Monitor</b> reports competitor prices, gaps and changes. <b>Suggest</b> adds a guarded suggested price per product for you to approve. <b>Automatic</b> marks rule prices as ready to push; nothing is written to your shop unless you also turn on <i>Write new prices to my shop</i>.

## `strategy` (type: `string`):

Applied to the lowest comparable competitor price (same currency, in stock).

## `undercutPercent` (type: `number`):

Used by "Undercut by a percentage".

## `undercutAmount` (type: `number`):

Used by "Undercut by an amount", in the product's currency.

## `premiumPercent` (type: `number`):

Used by "Stay above the lowest competitor".

## `minMarginPercent` (type: `number`):

For products with a <code>costPrice</code>: never suggest below cost / (1 - margin). 0 = never below cost. Example: 30 keeps at least a 30% margin.

## `floorPrice` (type: `number`):

Never suggest below this price. A product's own <code>floorPrice</code> wins over this value.

## `maxChangePercent` (type: `number`):

A suggestion never moves more than this from your current price in one run (protects against a competitor's pricing error).

## `allowPriceIncrease` (type: `boolean`):

When competitors are more expensive, suggest raising your price towards them (still capped by max change). Turn off to only ever lower prices.

## `ignoreOutOfStock` (type: `boolean`):

Out-of-stock or discontinued offers are reported but not used for suggestions.

## `pushToShop` (type: `boolean`):

Only in Automatic mode, and only when a rule changes a price. Each successful update is a <code>price-pushed</code> event. Leave off to get the price suggestions only (recommended until you trust your rules).

## `shopPlatform` (type: `string`):

Where new prices are written.

## `shopifyDomain` (type: `string`):

Your <code>your-store.myshopify.com</code> domain (not the custom domain).

## `shopifyAccessToken` (type: `string`):

Custom app token (shpat\_...) with the <code>write_products</code> scope. Stored encrypted; never written to the dataset, logs or key-value store.

## `wooBaseUrl` (type: `string`):

e.g. <code>https://myshop.com</code> (https required).

## `wooConsumerKey` (type: `string`):

REST API key (ck\_...) with Read/Write permission. Stored encrypted.

## `wooConsumerSecret` (type: `string`):

REST API secret (cs\_...). Stored encrypted.

## `webhookUrl` (type: `string`):

https URL that receives a JSON POST per price change (<code>sku, variantId, shopProductId, oldPrice, newPrice, currency, reason</code>). Secret because webhook URLs often contain a token.

## `webhookSecret` (type: `string`):

Optional. Adds an <code>X-CPM-Signature: sha256=\<HMAC of the body></code> header so your endpoint can verify the request.

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

Optional list of competitor shop home pages (<code>{"name": "Shop", "url": "https://shop.example"}</code>). For each product the Actor searches the shop by EAN or name and keeps only result pages that match the product (EAN or title). Shops whose robots.txt disallows search (e.g. Shopify) are skipped. Accurate competitor URLs in your catalog are faster and more reliable.

## `maxDiscoveredPerProduct` (type: `integer`):

Per product and shop.

## `respectRobotsTxt` (type: `boolean`):

Skip pages a shop's robots.txt disallows (reported as robots_disallowed, not charged).

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

Products checked in parallel. Requests to the same shop always run one at a time with a short pause (and honour Crawl-delay).

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

Per page.

## `historyStoreName` (type: `string`):

Named key-value store in your account that keeps the price history between runs (used for "change since last run"). Use a different name per catalog or schedule.

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

Optional Apify proxy, e.g. to see prices of a specific country. Not a way around bot protection: blocked pages stay blocked.

## Actor input object example

```json
{
  "products": [
    {
      "sku": "BOOK-ATTIC",
      "name": "A Light in the Attic",
      "yourPrice": 49.99,
      "currency": "GBP",
      "costPrice": 20,
      "competitors": [
        {
          "name": "Books to Scrape",
          "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"
        }
      ]
    },
    {
      "sku": "BOOK-VELVET",
      "name": "Tipping the Velvet",
      "yourPrice": 55,
      "currency": "GBP",
      "costPrice": 25,
      "competitors": [
        {
          "name": "Books to Scrape",
          "url": "https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html"
        }
      ]
    },
    {
      "sku": "RUNNER-TREE-M8",
      "name": "Men's Tree Runner (size 8)",
      "yourPrice": 105,
      "currency": "USD",
      "costPrice": 45,
      "competitors": [
        {
          "name": "Allbirds (Shopify)",
          "url": "https://www.allbirds.com/products/mens-tree-runners"
        }
      ]
    }
  ],
  "defaultCurrency": "EUR",
  "maxProducts": 100,
  "maxCompetitorsPerProduct": 10,
  "mode": "suggest",
  "strategy": "undercut_percent",
  "undercutPercent": 2,
  "undercutAmount": 1,
  "premiumPercent": 5,
  "minMarginPercent": 0,
  "maxChangePercent": 15,
  "allowPriceIncrease": true,
  "ignoreOutOfStock": true,
  "pushToShop": false,
  "shopPlatform": "none",
  "maxDiscoveredPerProduct": 2,
  "respectRobotsTxt": true,
  "maxConcurrency": 5,
  "requestTimeoutSecs": 20,
  "historyStoreName": "competitor-price-monitor-history",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

One row per product: lowest competitor, gap, position, change since last run and suggested price.

## `competitors` (type: `string`):

One row per competitor page: price, currency, stock, change since last run, status (blocked / no_price pages are free).

## `repricing` (type: `string`):

Suggested prices with the guards applied, and shop push results.

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

Counts (pages priced, blocked, robots-disallowed), charges and warnings.

# 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": [
        {
            "sku": "BOOK-ATTIC",
            "name": "A Light in the Attic",
            "yourPrice": 49.99,
            "currency": "GBP",
            "costPrice": 20,
            "competitors": [
                {
                    "name": "Books to Scrape",
                    "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"
                }
            ]
        },
        {
            "sku": "BOOK-VELVET",
            "name": "Tipping the Velvet",
            "yourPrice": 55,
            "currency": "GBP",
            "costPrice": 25,
            "competitors": [
                {
                    "name": "Books to Scrape",
                    "url": "https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html"
                }
            ]
        },
        {
            "sku": "RUNNER-TREE-M8",
            "name": "Men's Tree Runner (size 8)",
            "yourPrice": 105,
            "currency": "USD",
            "costPrice": 45,
            "competitors": [
                {
                    "name": "Allbirds (Shopify)",
                    "url": "https://www.allbirds.com/products/mens-tree-runners"
                }
            ]
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("prevailing_glow/competitor-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 = { "products": [
        {
            "sku": "BOOK-ATTIC",
            "name": "A Light in the Attic",
            "yourPrice": 49.99,
            "currency": "GBP",
            "costPrice": 20,
            "competitors": [{
                    "name": "Books to Scrape",
                    "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
                }],
        },
        {
            "sku": "BOOK-VELVET",
            "name": "Tipping the Velvet",
            "yourPrice": 55,
            "currency": "GBP",
            "costPrice": 25,
            "competitors": [{
                    "name": "Books to Scrape",
                    "url": "https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html",
                }],
        },
        {
            "sku": "RUNNER-TREE-M8",
            "name": "Men's Tree Runner (size 8)",
            "yourPrice": 105,
            "currency": "USD",
            "costPrice": 45,
            "competitors": [{
                    "name": "Allbirds (Shopify)",
                    "url": "https://www.allbirds.com/products/mens-tree-runners",
                }],
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("prevailing_glow/competitor-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 '{
  "products": [
    {
      "sku": "BOOK-ATTIC",
      "name": "A Light in the Attic",
      "yourPrice": 49.99,
      "currency": "GBP",
      "costPrice": 20,
      "competitors": [
        {
          "name": "Books to Scrape",
          "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"
        }
      ]
    },
    {
      "sku": "BOOK-VELVET",
      "name": "Tipping the Velvet",
      "yourPrice": 55,
      "currency": "GBP",
      "costPrice": 25,
      "competitors": [
        {
          "name": "Books to Scrape",
          "url": "https://books.toscrape.com/catalogue/tipping-the-velvet_999/index.html"
        }
      ]
    },
    {
      "sku": "RUNNER-TREE-M8",
      "name": "Men'\''s Tree Runner (size 8)",
      "yourPrice": 105,
      "currency": "USD",
      "costPrice": 45,
      "competitors": [
        {
          "name": "Allbirds (Shopify)",
          "url": "https://www.allbirds.com/products/mens-tree-runners"
        }
      ]
    }
  ]
}' |
apify call prevailing_glow/competitor-price-monitor --silent --output-dataset

```

## MCP server setup

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