# Price & Stock Change Monitor – Alerts for Any Product Page (`filexy634/price-stock-monitor`) Actor

Monitor product prices and stock on any online shop. Get only what changed: price drops, price increases, back in stock, out of stock and target-price hits. Schedule it, send alerts to Slack, Discord or a webhook, and pay only for products successfully checked.

- **URL**: https://apify.com/filexy634/price-stock-monitor.md
- **Developed by:** [Felix Masomera](https://apify.com/filexy634) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 product-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

## Price & Stock Change Monitor

Watch any list of product pages and get **only what changed**: price drops, price increases, back-in-stock, out-of-stock, and target-price hits. Schedule it daily or hourly and send alerts to Slack, Discord or any webhook.

### How it works

1. Give it product URLs.
2. The first run records a baseline price for each product (`new`).
3. Every later run compares against the previous run and writes only products that changed.
4. Optional: one summary alert per run to your webhook.

Prices are detected automatically from the structured data most shops publish (JSON-LD, Open Graph product tags, schema.org microdata). For shops without it, add a CSS selector per URL.

### Input

Each product URL can carry optional settings in its `userData`:

```json
{ "url": "https://shop.example/p/123", "userData": { "priceSelector": ".price", "stockSelector": ".availability", "targetPrice": 49.99 } }
```

| Field | Description |
|---|---|
| `startUrls` | Product pages to monitor |
| `minChangePercent` | Ignore smaller price moves (the baseline only moves when a change is reported) |
| `outputUnchanged` | Also output products with no change (off by default) |
| `stateStoreName` | Name of the watchlist. Use a different name per separate list |
| `webhookUrl` / `webhookFormat` | Alert destination: generic JSON, Slack or Discord |
| `defaultCurrency` | Currency to assume when only a CSS selector provides the price |
| `proxyConfiguration` | Optional. Some shops need residential proxies |

### Output

```json
{
  "url": "https://shop.example/p/123",
  "name": "Anvil 20kg",
  "changeType": "price_drop",
  "changes": ["price_drop", "target_hit"],
  "price": 79.99,
  "previousPrice": 99.99,
  "priceChangePercent": -20,
  "lowestPrice": 79.99,
  "currency": "USD",
  "availability": "in_stock"
}
```

Products that fail (page gone, no price found, blocked) appear with `status: "error"` and are **not charged**.

### Pricing

Charged per product successfully checked, plus a small fee per alert delivered.

### Limitations

- Static HTML only. Prices rendered purely by client-side JavaScript are not detected, and shops with strong bot protection may block requests.
- Price history is kept for the last 30 reported price changes per product.
- Respect each shop's terms of service and robots rules, and keep check frequency reasonable.

### Developer notes

Events to create in Console → Monetization (delete the default `apify-default-dataset-item` event, otherwise error rows get billed):

- `product-checked` (suggested start: $0.002)
- `alert-sent` (suggested start: $0.01)

# Actor input Schema

## `startUrls` (type: `array`):

Product pages to monitor. Prices are detected automatically from structured data. For sites without it, add a CSS selector in the item's userData, e.g. {"priceSelector": ".price", "stockSelector": ".availability", "targetPrice": 49.99}.

## `minChangePercent` (type: `number`):

Ignore price changes smaller than this percentage. 0 reports every change. The baseline only moves when a change is reported, so slow drifts still trigger once they add up.

## `outputUnchanged` (type: `boolean`):

Also write products whose price and stock did not change. Off by default so the dataset only contains news.

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

Name of the storage that remembers previous prices between runs. Use a different name for each separate watchlist. Lowercase letters, numbers and hyphens only.

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

Optional. One summary message is sent after each run that detected changes. Works with Slack, Discord or any HTTP endpoint.

## `webhookFormat` (type: `string`):

Payload shape sent to the webhook URL.

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

Three-letter code (e.g. USD, EUR, PLN) used when a price comes from a CSS selector and no currency can be detected.

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

How many product pages are fetched in parallel. Lower it if a shop rate-limits you.

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

Optional. Some shops block data-center traffic; residential proxies help there but cost extra.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
      "userData": {
        "priceSelector": ".price_color",
        "stockSelector": ".availability"
      }
    }
  ],
  "minChangePercent": 0,
  "outputUnchanged": false,
  "stateStoreName": "price-monitor-state",
  "webhookFormat": "json",
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `changes` (type: `string`):

Dataset of product checks with price and stock changes.

# 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 = {
    "startUrls": [
        {
            "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
            "userData": {
                "priceSelector": ".price_color",
                "stockSelector": ".availability"
            }
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("filexy634/price-stock-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 = {
    "startUrls": [{
            "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
            "userData": {
                "priceSelector": ".price_color",
                "stockSelector": ".availability",
            },
        }],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("filexy634/price-stock-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 '{
  "startUrls": [
    {
      "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
      "userData": {
        "priceSelector": ".price_color",
        "stockSelector": ".availability"
      }
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call filexy634/price-stock-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,filexy634/price-stock-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/jzBqhAnccKP0QYYzl/builds/tx5YShkFmez7SAJNv/openapi.json
