# Bunnings Price & Stock Change Monitor (per store) (`datadeltas/bunnings-monitor`) Actor

Watch Bunnings products and get ONLY the changes: price rises/drops and per-store stock movements, per storeId. Schedule daily and feed alerts, repricing or buying decisions.

- **URL**: https://apify.com/datadeltas/bunnings-monitor.md
- **Developed by:** [Daniel Matthee](https://apify.com/datadeltas) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.50 / 1,000 change detecteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Bunnings Price & Stock Change Monitor (per store)

Watch any set of Bunnings (bunnings.com.au) products and get **only what
changed since the last run**: price rises, price drops, and per-store stock
movements — checked directly against Bunnings' own product APIs, per
`storeId`, as often as you schedule it (daily works great).

Existing Bunnings actors are one-shot scrapers: they hand you thousands of
rows and leave the "what's different?" work to you. This monitor keeps a
baseline between runs and emits a clean change feed instead — ideal for
alerting, repricing and buying decisions.

- **First run** seeds the baseline and emits nothing (clearly logged).
- **Every later run** emits one record per changed field per store.
- A product that vanishes from the site emits a stock change to
  `"unavailable"` — exactly once.

### Example change record

```json
{
  "sku": "0299328",
  "name": "Ozito 710W Hammer Drill",
  "field": "price",
  "oldValue": 53.98,
  "newValue": 49.98,
  "storeId": "6400",
  "productUrl": "https://www.bunnings.com.au/ozito-710w-hammer-drill_p0299328",
  "detectedAt": "2026-08-31T02:15:04Z"
}
```

Stock changes look the same with `"field": "stock"` and values
`in_stock` / `out_of_stock` / `unavailable`.

### Input options

| Field | Type | Default | What it does |
| --- | --- | --- | --- |
| `watchUrls` | array | `[]` | Bunnings product page URLs to watch (product code is read from the `_p0299328` suffix). |
| `watchQueries` | array | `[]` | Bunnings search terms; every matching product is added to the watch list. |
| `storeIds` | array | `["6400"]` | Store location codes to check price and stock at. One feed entry per product per store. |
| `maxItems` | integer | `500` | Cap on change records emitted per run. |
| `maxProductsPerQuery` | integer | `25` | How many products each query may add. |
| `stateStoreName` | string | `bunnings-monitor-state` | Named key-value store holding the baseline; use different names for independent watch lists. |
| `proxyConfiguration` | object | Apify residential (AU) | Bunnings sits behind Cloudflare — keep Australian residential proxies on. |

### Use cases

- **Trade buyers**: watch your consumables list (fixings, sealants, timber,
  PPE) at your two nearest stores and get pinged the morning a price drops or
  stock lands, before you send the ute.
- **Resellers & price-matchers**: track competitor-relevant SKUs per store and
  feed the change records straight into your repricing sheet — no diffing of
  full catalogue dumps.
- **Ranging & availability watch**: suppliers and category analysts get a
  clean audit trail of when a product went `out_of_stock`, came back, or was
  delisted (`unavailable`) at specific stores.

### Pricing (pay per event)

| Event | Price | Charged when |
| --- | --- | --- |
| Actor start | $0.005 | Once per run. |
| Change detected | $0.015 | Per change record emitted. |
| Item checked | $0.0002 | Per product/store pair checked. |

A daily watch of 100 products at 2 stores costs about $0.045/run in checks
plus $0.015 per actual change — you pay for signal, not for pages.

### Scheduling

Run it on an Apify Schedule (e.g. daily at 6:00 Australia/Sydney). State
lives in a named key-value store, so every scheduled run diffs against the
previous one automatically.

### Update & maintenance promise

Bunnings' API schema is checked weekly; parser drift is logged (never
crashes a run) and fixed promptly. Field set above is stable — new fields
are only ever added.

### Changelog

- **0.1** (2026-08-31) — Initial release: price + per-store stock change
  feed, named-KV baseline, pay-per-event pricing.

# Actor input Schema

## `watchUrls` (type: `array`):

Bunnings product page URLs, e.g. https://www.bunnings.com.au/ozito-710w-hammer-drill\_p0299328. The product code is read from the \_p… suffix.

## `watchQueries` (type: `array`):

Bunnings search terms. Every product returned for each query (up to Max products per query) is added to the watch list.

## `storeIds` (type: `array`):

Bunnings store location codes to check prices and stock at (the number in the store's page URL / API locationCode, e.g. 6400 = Mentone VIC, 2130 = Maddington WA). One change feed entry per product per store.

## `maxItems` (type: `integer`):

Cap on change records emitted in one run. Keeps test runs and first big diffs cheap.

## `maxProductsPerQuery` (type: `integer`):

How many products each search query may add to the watch list.

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

Named key-value store holding the last-seen baseline. Use different names to run independent watch lists.

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

Bunnings sits behind Cloudflare; Australian residential proxies are the reliable path.

## Actor input object example

```json
{
  "watchUrls": [
    "https://www.bunnings.com.au/ozito-710w-hammer-drill_p0299328"
  ],
  "watchQueries": [],
  "storeIds": [
    "6400"
  ],
  "maxItems": 500,
  "maxProductsPerQuery": 25,
  "stateStoreName": "bunnings-monitor-state",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "AU"
  }
}
```

# Actor output Schema

## `records` (type: `string`):

No description

# 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 = {
    "watchUrls": [
        "https://www.bunnings.com.au/ozito-710w-hammer-drill_p0299328"
    ],
    "watchQueries": [],
    "storeIds": [
        "6400"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "AU"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datadeltas/bunnings-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 = {
    "watchUrls": ["https://www.bunnings.com.au/ozito-710w-hammer-drill_p0299328"],
    "watchQueries": [],
    "storeIds": ["6400"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "AU",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("datadeltas/bunnings-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 '{
  "watchUrls": [
    "https://www.bunnings.com.au/ozito-710w-hammer-drill_p0299328"
  ],
  "watchQueries": [],
  "storeIds": [
    "6400"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "AU"
  }
}' |
apify call datadeltas/bunnings-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datadeltas/bunnings-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/R0z5O7Tnpj7soBbvd/builds/5FMqenSm6hI2wlfkZ/openapi.json
