# Universal Price & Availability Change Monitor (`swholmes/universal-change-monitor`) Actor

Monitor any web page or product URL for changes. Returns a structured diff and can POST alerts to a webhook. Scheduled, recurring, pay-per-event.

- **URL**: https://apify.com/swholmes/universal-change-monitor.md
- **Developed by:** [Scott Holmes](https://apify.com/swholmes) (community)
- **Categories:** Automation, Developer tools, E-commerce
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 url 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/platform/actors/running/actors-in-store#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

## Universal Price & Availability Change Monitor

Watch any list of web pages for changes. On each run the Actor fetches every target, extracts a signal (raw content, a price, or a stock status), compares it to the snapshot saved from the previous run, and reports anything that changed. Optionally POSTs each change to a webhook so you can wire it into Slack, email, n8n, or your own app.

Built to run on a schedule (for example hourly or daily). The first run stores a baseline; later runs produce diffs.

### Input

| Field | Type | Notes |
|---|---|---|
| `targets` | array | Required. `[{ "url": "...", "selector": ".price", "label": "..." }]`. `selector` and `label` are optional. |
| `mode` | string | `content` (any text change), `price` (first price-like value), or `availability` (in/out of stock). |
| `webhookUrl` | string | Optional. Each change is POSTed here as JSON. |
| `renderJs` | boolean | Turn on for client-side-rendered pages. Slower, uses a headless browser. |
| `proxyConfiguration` | object | Apify Proxy config. Residential recommended for defended targets. |

### Output

One dataset record per detected change:

```json
{
  "label": "Widget product page",
  "url": "https://shop.example.com/widget",
  "selector": ".price",
  "mode": "price",
  "changed": true,
  "changeType": "price",
  "before": "$19.99",
  "after": "$17.49",
  "checkedAt": "2026-07-11T14:03:00.000Z"
}
```

### Monetization (pay-per-event)

The code charges two events; define their prices in the Apify Console under Monetization:

- `url-checked` — charged once per target per run (covers compute/proxy).
- `change-detected` — charged only when an actual change is found (the value moment).

This lets you price cheap polling with a premium on useful hits.

### How it works

Snapshots are stored in a named Key-Value Store (`change-monitor-snapshots`), keyed on `url + selector`, so diffs survive across scheduled runs. Content mode compares normalized text (capped at 20k chars to keep runs cheap); price mode extracts the first currency-like token; availability mode looks for stock keywords.

### Notes / next steps

- Add per-target `mode` if you want to mix price and content watches in one run.
- Add a "changed lines" diff (currently reports before/after values) if subscribers want granular content diffs.
- For heavily defended targets, enable `renderJs` and residential proxies.

# Actor input Schema

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

One entry per page to watch. `url` is required. `selector` narrows monitoring to a CSS region (recommended for price/stock). `label` names the target in output.

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

content = any text change in the selected region. price = extract the first price-like number. availability = watch for in/out-of-stock keywords.

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

If set, a JSON payload is POSTed here for every detected change.

## `renderJs` (type: `boolean`):

Enable for pages that build content client-side. Slower and more expensive (uses a headless browser).

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

Proxy configuration. Residential proxies are recommended for defended targets.

## Actor input object example

```json
{
  "targets": [
    {
      "url": "https://example.com",
      "selector": "",
      "label": "Example homepage"
    }
  ],
  "mode": "content",
  "renderJs": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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://example.com",
            "selector": "",
            "label": "Example homepage"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("swholmes/universal-change-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://example.com",
            "selector": "",
            "label": "Example homepage",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("swholmes/universal-change-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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://example.com",
      "selector": "",
      "label": "Example homepage"
    }
  ]
}' |
apify call swholmes/universal-change-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=swholmes/universal-change-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/0ecn1cgC3OmNEYYqd/builds/13EGV452QS39TRPdO/openapi.json
