# Competitor Price & Promotion Monitor (`miasma_automation/competitor-price-promotion-monitor`) Actor

Track competitor prices, discounts, promotions, coupons, and stock changes over time. Create a baseline on the first run, then detect structured commercial changes on every scheduled check.

- **URL**: https://apify.com/miasma\_automation/competitor-price-promotion-monitor.md
- **Developed by:** [Miasma Automation](https://apify.com/miasma_automation) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 page checks

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

## Competitor Price & Promotion Monitor

Most scrapers tell you what a product page contains right now. Competitor Price & Promotion Monitor watches ecommerce pages over time and tells you what commercially changed.

Track competitor prices, discounts, promotions, coupons, and supported stock changes. Run once to create a baseline, then schedule recurring checks in Apify to see exactly what changed.

### What It Does

This Actor monitors product, category, and promotion pages and writes structured results to the Dataset. On the first run it stores the current state. On later runs it compares the latest page state against stored history and reports material commercial changes.

You do not need to configure scraping selectors or proxy settings.

### Who It's For

- Ecommerce brands tracking competitor offers
- Ecommerce agencies managing client watchlists
- Pricing teams watching price movement
- Merchandising teams monitoring sales and promos
- Competitive intelligence teams looking for market signals
- Marketplace and retail analysts comparing offers over time

### What It Tracks

- Price increases
- Price decreases
- Discount started
- Discount changed
- Discount ended
- Promotion started
- Promotion changed
- Promotion ended
- Coupon appeared
- Coupon removed
- Stock changes where supported
- Baseline state
- Grouped `OFFER_CHANGED` events

When several related changes happen at once, the Actor can return a grouped `OFFER_CHANGED` event with atomic supporting events such as `PRICE_DECREASE`, `DISCOUNT_STARTED`, or `PROMOTION_STARTED`.

### How It Works

1. Add competitor product, category, or promotion URLs.
2. Choose what to track.
3. Run the Actor once.
4. The first run creates a baseline.
5. Schedule the Actor in Apify to rerun automatically.
6. Future runs compare the new state with the previous state.
7. Material commercial changes are written to the Dataset.

### First Run: Create A Baseline

The first run creates the initial snapshot for each supported page.

There is no previous observation yet, so the Actor reports `BASELINE_CREATED` rather than pretending that "no changes" occurred. Change events begin on later runs with the same monitor identity or target configuration.

### Automatic Monitoring With Apify Schedules

Use Apify Schedules to run this Actor hourly, every few hours, daily, or weekly.

The Actor does not schedule itself. Each scheduled run loads stored history, checks the current page state, and reports new changes found during that run.

### Input

```json
{
  "targets": [
    {
      "url": "https://example.com/product/example-shoe",
      "label": "Competitor A"
    }
  ],
  "trackPrices": true,
  "trackPromotions": true,
  "trackCoupons": true,
  "trackStock": false,
  "minimumDiscountPercent": 0,
  "outputMode": "changes_and_snapshots"
}
```

`targets` is required. `monitorId` is optional and can be used as a stable identity for the same customer watchlist across future runs.

### Output

First run baseline:

```json
{
  "record_type": "BASELINE_CREATED",
  "target": "https://example.com/product/example-shoe",
  "competitor": "Competitor A",
  "snapshots": 1,
  "message": "Baseline created. No changes are reported until a later run compares against this history."
}
```

Subsequent run with a material offer change:

```json
{
  "record_type": "CHANGE_EVENT",
  "competitor": "Competitor A",
  "product_name": "Example Shoe",
  "event": "OFFER_CHANGED",
  "primary_change": "DISCOUNT_STARTED",
  "supporting_changes": [
    "PRICE_DECREASE",
    "PROMOTION_STARTED"
  ],
  "old_price": 200,
  "new_price": 150,
  "discount_percent": 25,
  "promotion_text": "25% OFF"
}
```

The Actor also emits `SNAPSHOT` records for current page state and `ERROR` records for unsupported or partially failing targets.

### Pricing

This Actor uses Pay Per Event pricing:

- Actor start: **$0.01 per run**
- Page checked: **$0.003 per successfully processed page**
- Detected changes: **included at no additional charge**

`page-checked` is the primary billing event. It is charged only after a page is successfully processed.

Example run costs:

- 10 pages: $0.01 + (10 x $0.003) = approximately $0.04 per run
- 100 pages: $0.01 + (100 x $0.003) = approximately $0.31 per run
- 1,000 pages: $0.01 + (1,000 x $0.003) = approximately $3.01 per run

If the Actor is scheduled repeatedly, each scheduled run is billed according to the pages successfully checked during that run.

### Why Use This Instead Of A Normal Scraper?

A normal scraper shows current page state.

This Actor remembers previous state, detects material commercial changes, calculates discounts, normalizes events, suppresses duplicate noise, and supports recurring monitoring.

### Limitations

- Optimized for HTTP-accessible ecommerce pages.
- Works best when useful product and price information is available in normal HTML or structured metadata.
- Some JavaScript-heavy sites may not work in V1.
- Authenticated or login-only pages are not supported.
- Restricted sources may be unsupported.
- Not every ecommerce website is guaranteed to work.
- No proxy bypass or CAPTCHA bypass is provided.

Unsupported pages return structured `ERROR` records instead of silent success.

### Support / Feedback

If a supported-looking ecommerce page does not parse correctly, share a sample URL and the expected price or promotion fields. New storefront patterns can usually be added as targeted parser improvements.

# Actor input Schema

## `targets` (type: `array`):

Product, category or promotion pages to monitor.

## `monitorId` (type: `string`):

Optional stable identity for this customer/configuration. Use the same value on future runs to compare against the same baseline history.

## `trackPrices` (type: `boolean`):

Detect regular price, sale price and discount changes.

## `trackPromotions` (type: `boolean`):

Detect visible promotion badges, banners and product-page offer text.

## `trackCoupons` (type: `boolean`):

Detect coupon or promo codes shown on the monitored pages.

## `trackStock` (type: `boolean`):

Detect availability changes such as in stock, out of stock or preorder.

## `minimumDiscountPercent` (type: `number`):

Only emit discount events at or above this discount percentage.

## `outputMode` (type: `string`):

Choose whether the dataset should contain snapshots, change events, or both.

## Actor input object example

```json
{
  "targets": [
    {
      "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
      "label": "Example competitor"
    }
  ],
  "trackPrices": true,
  "trackPromotions": true,
  "trackCoupons": true,
  "trackStock": false,
  "minimumDiscountPercent": 0,
  "outputMode": "changes_and_snapshots"
}
```

# Actor output Schema

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

Default dataset containing BASELINE\_CREATED, SNAPSHOT, CHANGE\_EVENT and ERROR records.

# 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 = {
    "targets": [
        {
            "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
            "label": "Example competitor"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("miasma_automation/competitor-price-promotion-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 = { "targets": [{
            "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
            "label": "Example competitor",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("miasma_automation/competitor-price-promotion-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 '{
  "targets": [
    {
      "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
      "label": "Example competitor"
    }
  ]
}' |
apify call miasma_automation/competitor-price-promotion-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,miasma_automation/competitor-price-promotion-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/QMoySOZvcrWB63LaS/builds/0la0h7V2ZcEv8xc9f/openapi.json
