# Shopify Price & Stock Delta Monitor (`stellar_ballet_0bu/shopify-delta-monitor`) Actor

Monitor Shopify stores via products.json for MAP compliance, repricing, competitor price drops, stock changes, and clean delta feeds with optional Slack/Discord alerts.

- **URL**: https://apify.com/stellar\_ballet\_0bu/shopify-delta-monitor.md
- **Developed by:** [Nikita S](https://apify.com/stellar_ballet_0bu) (community)
- **Categories:** E-commerce, Automation, AI
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-usage

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## Shopify Price & Stock Delta Monitor

Track Shopify product catalog changes and get a clean feed of **price, stock, new product, removed product, MAP-compliance, and high-severity price-drop deltas**.

This Actor is for e-commerce teams, agencies, resellers, price analysts, and automation builders who need competitor monitoring without building a custom monitoring backend.

**Three jobs this Actor does:**

1. **Competitor price-drop alerts** — detect 20%+ drops, rank them as `high`, and trigger a dedicated `price_drop_alert` event.
2. **MAP / repricing checks** — monitor public Shopify competitors for price moves below expected thresholds and feed the rows into Sheets, n8n, Make, or BI.
3. **Catalog change feed** — track new products, removed products, restocks, sold-out variants, and sale starts/ends.

**Pricing:** Pay Per Event. `$0.002` per emitted delta row is already scheduled. v0.3 also emits a `price_drop_alert` hook for 20%+ drops and a near-zero `apify-actor-start` hook, but Apify blocks another pricing-table change until **2026-08-06**; those extra hooks are code-ready and will become billable after the platform gate allows the pricing update. First run emits the full baseline (e.g. ~2,500 rows for a mid-size Shopify store) — about **$5 per store for the first snapshot, then fractions of a cent per day** for typical daily changes. No monthly minimums.

**Current build:** `0.3.0` (`delta_result` Pay Per Event pricing starts on `2026-07-21T23:43:19Z`; v0.3's extra pricing events are pending Apify's one-month pricing-change cooldown). See [`CHANGELOG.md`](./CHANGELOG.md) for the full version history.

**Maintainer:** DataFlow LV (Latvia-based data automation). Apify: [stellar_ballet_0bu](https://apify.com/stellar_ballet_0bu).


<!-- store-visuals:start -->

### Visual demo: Shopify Delta Monitor

<a href="https://api.apify.com/v2/key-value-stores/yjcSu1xOwpsFPXeto/records/shopify-delta-monitor-hero.svg" target="_blank"><img src="https://api.apify.com/v2/key-value-stores/yjcSu1xOwpsFPXeto/records/shopify-delta-monitor-hero.svg" alt="Shopify Delta Monitor visual overview" width="780"></a>

<a href="https://api.apify.com/v2/key-value-stores/yjcSu1xOwpsFPXeto/records/shopify-delta-monitor-workflow.svg" target="_blank"><img src="https://api.apify.com/v2/key-value-stores/yjcSu1xOwpsFPXeto/records/shopify-delta-monitor-workflow.svg" alt="Shopify Delta Monitor workflow diagram" width="780"></a>

<a href="https://api.apify.com/v2/key-value-stores/yjcSu1xOwpsFPXeto/records/shopify-delta-monitor-sample-output.svg" target="_blank"><img src="https://api.apify.com/v2/key-value-stores/yjcSu1xOwpsFPXeto/records/shopify-delta-monitor-sample-output.svg" alt="Shopify Delta Monitor sample output dataset row" width="620"></a>

These images are hosted in a persistent Apify key-value store so the Store README has stable, clickable visual previews.

<!-- store-visuals:end -->

### Why use this Actor?

Most Shopify scrapers return a full catalog every run. That is useful once, but noisy for monitoring.

This Actor is built for recurring runs:

- run once to create a baseline snapshot;
- schedule it daily or hourly;
- receive only what changed;
- classify changes as named events like `price_change`, `restock`, `sold_out`, `new_product`, `removed_product`, `sale_started`, and `sale_ended`;
- rank rows with `event_severity` (`low`, `medium`, `high`) so workflows can filter only serious price drops, stock-outs, and MAP/repricing events;
- optionally send one Slack or Discord alert summary per run;
- connect the delta feed to Google Sheets, Airtable, n8n, Make, Slack, email alerts, or a BI dashboard.

### Typical use cases

- Monitor competitor price changes.
- Detect sold-out and restocked variants.
- Track new products and removed products.
- Feed Shopify catalog changes into a reporting workflow.
- Build a lightweight price intelligence or merchandising alert system.

### What it does

For each Shopify store URL, the Actor:

1. Reads the public `/products.json` catalog endpoint.
2. Flattens products and variants into clean dataset rows.
3. Compares the current snapshot with the previous run.
4. Emits rows with `status`: `new`, `changed`, `removed`, `unchanged`, or `error`.
5. Saves the latest snapshot in a named Apify key-value store when `persistState` is enabled.

### Input example

```json
{
  "storeUrls": ["https://www.allbirds.com"],
  "maxPagesPerStore": 1,
  "onlyChanged": true,
  "persistState": true,
  "stateStoreName": "shopify-delta-monitor-state",
  "alertsEnabled": false,
  "minPriceChangePct": 0
}
````

#### Input fields

| Field | Description |
|---|---|
| `storeUrls` | Shopify store URLs. The Actor uses the host and reads `/products.json`. |
| `maxPagesPerStore` | How many `/products.json` pages to fetch. Each page can contain up to 250 products. |
| `onlyChanged` | If `true`, unchanged rows are skipped. New, changed, removed, and error rows are still emitted. |
| `persistState` | If `true`, the Actor saves the latest snapshot and uses it as the baseline next time. |
| `stateStoreName` | Named Apify key-value store for snapshots. |
| `stateKey` | Optional snapshot key override. Leave empty to use one key per store host. |
| `previousItems` | Optional manual previous snapshot rows for one-off comparisons or migration. |
| `minPriceChangePct` | Minimum absolute price-change percentage required for a `price_change` event. |
| `alertsEnabled` | Send a webhook summary after the run if a Slack or Discord webhook is provided. |
| `slackWebhookUrl` | Optional Slack incoming webhook URL. |
| `discordWebhookUrl` | Optional Discord webhook URL. |
| `alertTopLimit` | Number of top changes included in the alert summary. |

### Output example

One dataset row represents one product variant delta:

```json
{
  "storeHost": "www.allbirds.com",
  "storeUrl": "https://www.allbirds.com",
  "productId": "123456789",
  "variantId": "987654321",
  "handle": "mens-runner",
  "title": "Men's Runner",
  "vendor": "Allbirds",
  "productType": "Shoes",
  "variantTitle": "10",
  "sku": "RUNNER-10",
  "price": 98,
  "compareAtPrice": 120,
  "available": true,
  "productUrl": "https://www.allbirds.com/products/mens-runner",
  "checkedAt": "2026-07-06T21:41:41.000Z",
  "status": "changed",
  "event": "price_change",
  "events": ["price_change", "restock"],
  "event_severity": "high",
  "changes": [
    { "field": "price", "before": 120, "after": 98 },
    { "field": "available", "before": false, "after": true }
  ]
}
```

The Actor also writes a `SUMMARY` key-value-store record:

```json
[
  {
    "storeUrl": "https://www.allbirds.com",
    "variantsSeen": 2489,
    "newOrChanged": 0,
    "removed": 0,
    "stateSaved": true,
    "stateKey": "snapshot-www.allbirds.com",
    "error": null
  }
]
```

### How to use it as a monitor

1. Run the Actor once with `persistState: true` to create the baseline snapshot.
2. Schedule it from Apify Console.
3. Keep `onlyChanged: true` so future runs emit only deltas.
4. Send the dataset output to Google Sheets, Slack, Airtable, n8n, Make, or your API.

### Integration ideas

- **Apify schedule → Google Sheets**: daily product change log.
- **Apify webhook → n8n → Slack**: alert when a competitor changes price or restocks.
- **Dataset API → BI dashboard**: price and availability trend reporting.
- **Agency workflow**: monitor 3–5 competitor Shopify stores for a client and send a weekly change report.

### Ready-made workflow assets

The Actor repository includes example assets you can copy into your own workflow:

- `examples/n8n-shopify-delta-to-slack.json` — starter n8n workflow: run Actor → check deltas → send Slack alert.
- `examples/google-sheets-template.csv` — column layout for Google Sheets.
- `examples/client-report-template.md` — simple weekly report structure for agencies and e-commerce teams.
- `docs/sample-dataset.md` — real example output: first-run baseline (2,489 rows) + repeat-run stateful delta (0 rows) from a live Allbirds run.

### Run it from Claude / Cursor / VS Code via MCP

The Actor is available through the Apify MCP server, so you can ask your AI assistant to "monitor this Shopify store and email me the deltas" instead of wiring it manually.

Add this to your MCP client config (for example `claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "apify": {
      "command": "npx",
      "args": ["-y", "@apify/mcp-server"],
      "env": {
        "APIFY_TOKEN": "your-apify-api-token"
      }
    }
  }
}
```

Once connected, the assistant can discover this Actor and trigger runs with a plain prompt like *"Run Shopify Delta Monitor on https://www.allbirds.com and show me the new products and price drops."* The remote MCP server at `https://mcp.apify.com` works the same way without a local install.

### Slack / Discord alert preview

When `alertsEnabled` is on and a webhook URL is provided, the Actor sends one compact summary after the run:

```text
Shopify delta monitor found 12 changes

price_change: 6, restock: 3, sold_out: 2, new_product: 1

Stores:
https://example-store.com: 11 new/changed, 1 removed

Top changes:
• Product A / Medium: price_change price 120 → 98
• Product B / Large: restock restocked
```

Webhook URLs are configured as secret input fields.

### Limitations

- Works only for Shopify stores exposing public `/products.json`.
- It does not bypass login, paywalls, CAPTCHA, Cloudflare, or other anti-bot systems.
- Inventory precision depends on what the Shopify catalog exposes; `available` is a boolean, not guaranteed stock quantity.
- Users are responsible for checking target-store terms and lawful use.

### Best first run

Use a small test first:

```json
{
  "storeUrls": ["https://www.allbirds.com"],
  "maxPagesPerStore": 1,
  "onlyChanged": true,
  "persistState": true
}
```

Run it twice. The first run creates the baseline; the second run should return only real changes.

### FAQ

**What changed in v0.3?**
Rows now include `event_severity`, and 20%+ price drops trigger a separate `price_drop_alert` event. The Store positioning now targets MAP-compliance, repricing checks, and serious price-drop monitoring — the use cases with clearer willingness to pay.

**Does it work on any Shopify store?**
On every Shopify store that exposes the public `/products.json` endpoint. The vast majority do, including all default themes. Custom-locked catalogs or stores behind Cloudflare bot protection will return an error row.

**Can it monitor non-Shopify sites?**
No. This Actor is Shopify-specific on purpose — the wedge is a clean stateful delta, not a generic scraper.

**How accurate is the stock signal?**
`available` is the same boolean Shopify exposes in the public catalog. It is not a warehouse count, and stores that use strict inventory apps may mask stock-outs. If you need exact quantities, this Actor is the wrong tool.

**Does it need login, cookies, or a headless browser?**
No. The Actor reads the same public JSON endpoint the store's own theme uses. No CAPTCHA bypass, no anti-bot evasion, no PII scraping.

**How do I get the data into Google Sheets / n8n / Slack?**
Either consume the dataset via the Apify API, or pass `previousItems` from one run into the next, or wire a webhook on the dataset. The `examples/` folder has a starter n8n workflow and a Sheets CSV template.

**Can I monitor multiple stores in one run?**
Yes. Pass an array of store URLs in `storeUrls`. The Actor creates one snapshot key per host by default, so they don't interfere.

**Why is the first run so much more expensive than later runs?**
The first run emits every variant as a `new_product` row (the baseline). Subsequent runs emit only the deltas. This is by design — you pay for the data, not for crawling.

**What's the difference vs. `shopify-discount-scanner` and similar Actors?**
That Actor is price+stock-only and bundles Slack/Discord alerts into the same code path. This Actor uses a named event taxonomy (`price_change`, `restock`, `sold_out`, `new_product`, `removed_product`, `sale_started`, `sale_ended`), persists state in your own Apify key-value store, and treats the delta feed as a primary deliverable (output schema + SUMMARY record) rather than a side effect. Use whichever fits your workflow.

### Support

- Issues and feature requests: open a GitHub issue on the Actor's repository, or message DataFlow LV via the Apify Console Actor page.
- Custom integrations (Sheets, n8n, Make, Slack, custom webhooks) and agency retainers: contact via the Apify Console Actor page.

### Quick start

1. Open this Actor in Apify Console.
2. Paste one or more Shopify store URLs into the input.
3. Keep `persistState` enabled for scheduled monitoring.
4. Run once to create the baseline snapshot.
5. Run again on a schedule to receive only delta rows.
6. Export the dataset to CSV/JSON, or send it to Google Sheets, n8n, Make, Slack, Discord, or a webhook.

### Sample output

Use this sample dataset to see the output shape before running it yourself:

- Sample dataset: https://console.apify.com/storage/datasets/uvIVdB6EoysJkzTbP

The important fields for automation are `event`, `events`, `event_severity`, `status`, and `changes`. Filter for `event_severity = high` when you only want alerts that deserve immediate attention.

### Pricing and cost expectations

This Actor is designed for scheduled monitoring and delta-only outputs. It avoids charging or processing unchanged rows where possible. Pay-Per-Event pricing is scheduled/used for meaningful emitted deltas such as new items, removed items, price changes, stock changes, URL changes, or pricing-plan changes depending on the Actor.

Start with a small input list first. Once the baseline looks correct, schedule recurring runs and set a reasonable max charge limit in Apify.

### Which monitor should I use?

This Actor is part of a focused monitoring portfolio. Pick the narrowest Actor that matches your source:

| Source you have | Use this Actor | Best for |
|---|---|---|
| Shopify store | [Shopify Delta Monitor](https://apify.com/stellar_ballet_0bu/shopify-delta-monitor) | Shopify competitor price/stock/sale monitoring |
| WooCommerce store | [WooCommerce Delta Monitor](https://apify.com/stellar_ballet_0bu/woocommerce-delta-monitor) | WooCommerce Store API product deltas |
| Product page URLs with Schema.org JSON-LD | [Schema.org Product Delta Monitor](https://apify.com/stellar_ballet_0bu/schema-product-delta-monitor) | Magento, BigCommerce, custom stores, marketplaces |
| Product feeds / APIs / CSV / XML | [Product Feed Delta Monitor](https://apify.com/stellar_ballet_0bu/product-feed-delta-monitor) | Supplier feeds, affiliate feeds, Google Merchant exports |
| sitemap.xml | [Sitemap Delta Monitor](https://apify.com/stellar_ballet_0bu/sitemap-delta-monitor) | SEO, content ops, RAG indexing queues |
| SaaS pricing pages | SaaS Pricing Page Monitor | Plan/price/feature changes on public pricing pages |

All monitors are built for scheduled runs, stateful comparisons, delta-only outputs, and workflow automation via Google Sheets, n8n, Make, Slack, Discord, or webhooks.

# Actor input Schema

## `storeUrls` (type: `array`):

Shopify store home/category/product URLs. The Actor will try /products.json on each host.

## `previousItems` (type: `array`):

Optional previous dataset items from an earlier run. Used to compute deltas.

## `maxPagesPerStore` (type: `integer`):

Maximum number of /products.json pages to fetch per store. Each page can contain up to 250 products.

## `onlyChanged` (type: `boolean`):

If enabled, rows with status unchanged are skipped. New, changed, removed, and error rows are still emitted.

## `persistState` (type: `boolean`):

Store the latest snapshot in a named key-value store so scheduled runs automatically emit only deltas next time.

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

Named key-value store used for snapshots when persistState is enabled.

## `stateKey` (type: `string`):

Optional snapshot key. Leave empty to use one key per Shopify store host.

## `minPriceChangePct` (type: `number`):

Minimum absolute percentage price change needed to emit a price\_change event. Set 0 to report every price change.

## `alertsEnabled` (type: `boolean`):

If enabled and a Slack or Discord webhook URL is provided, the Actor posts one summary message after the run.

## `slackWebhookUrl` (type: `string`):

Optional Slack incoming webhook URL. Kept secret by Apify input UI.

## `discordWebhookUrl` (type: `string`):

Optional Discord webhook URL. Kept secret by Apify input UI.

## `alertTopLimit` (type: `integer`):

Maximum number of top delta rows included in the Slack/Discord alert summary.

## Actor input object example

```json
{
  "storeUrls": [
    "https://www.allbirds.com"
  ],
  "previousItems": [],
  "maxPagesPerStore": 3,
  "onlyChanged": true,
  "persistState": true,
  "stateStoreName": "shopify-delta-monitor-state",
  "stateKey": "",
  "minPriceChangePct": 0,
  "alertsEnabled": false,
  "alertTopLimit": 5
}
```

# Actor output Schema

## `deltaRows` (type: `string`):

Default dataset items with product variant status, price, availability, URL, named events, event\_severity, and changes array.

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

Per-store summary with variants seen, new/changed count, removed count, event counters, state key, and errors.

# 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 = {
    "storeUrls": [
        "https://www.allbirds.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("stellar_ballet_0bu/shopify-delta-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 = { "storeUrls": ["https://www.allbirds.com"] }

# Run the Actor and wait for it to finish
run = client.actor("stellar_ballet_0bu/shopify-delta-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 '{
  "storeUrls": [
    "https://www.allbirds.com"
  ]
}' |
apify call stellar_ballet_0bu/shopify-delta-monitor --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Shopify Price & Stock Delta Monitor",
        "description": "Monitor Shopify stores via products.json for MAP compliance, repricing, competitor price drops, stock changes, and clean delta feeds with optional Slack/Discord alerts.",
        "version": "0.3",
        "x-build-id": "qcgsMYYFYAmfJzXqR"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/stellar_ballet_0bu~shopify-delta-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-stellar_ballet_0bu-shopify-delta-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/stellar_ballet_0bu~shopify-delta-monitor/runs": {
            "post": {
                "operationId": "runs-sync-stellar_ballet_0bu-shopify-delta-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/stellar_ballet_0bu~shopify-delta-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-stellar_ballet_0bu-shopify-delta-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "storeUrls"
                ],
                "properties": {
                    "storeUrls": {
                        "title": "Shopify store URLs",
                        "type": "array",
                        "description": "Shopify store home/category/product URLs. The Actor will try /products.json on each host.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "previousItems": {
                        "title": "Previous items",
                        "type": "array",
                        "description": "Optional previous dataset items from an earlier run. Used to compute deltas.",
                        "default": []
                    },
                    "maxPagesPerStore": {
                        "title": "Max products.json pages per store",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "Maximum number of /products.json pages to fetch per store. Each page can contain up to 250 products.",
                        "default": 3
                    },
                    "onlyChanged": {
                        "title": "Only output changed items",
                        "type": "boolean",
                        "description": "If enabled, rows with status unchanged are skipped. New, changed, removed, and error rows are still emitted.",
                        "default": true
                    },
                    "persistState": {
                        "title": "Persist state between runs",
                        "type": "boolean",
                        "description": "Store the latest snapshot in a named key-value store so scheduled runs automatically emit only deltas next time.",
                        "default": true
                    },
                    "stateStoreName": {
                        "title": "State store name",
                        "type": "string",
                        "description": "Named key-value store used for snapshots when persistState is enabled.",
                        "default": "shopify-delta-monitor-state"
                    },
                    "stateKey": {
                        "title": "State key override",
                        "type": "string",
                        "description": "Optional snapshot key. Leave empty to use one key per Shopify store host.",
                        "default": ""
                    },
                    "minPriceChangePct": {
                        "title": "Minimum price change %",
                        "minimum": 0,
                        "type": "number",
                        "description": "Minimum absolute percentage price change needed to emit a price_change event. Set 0 to report every price change.",
                        "default": 0
                    },
                    "alertsEnabled": {
                        "title": "Send webhook alert summary",
                        "type": "boolean",
                        "description": "If enabled and a Slack or Discord webhook URL is provided, the Actor posts one summary message after the run.",
                        "default": false
                    },
                    "slackWebhookUrl": {
                        "title": "Slack webhook URL",
                        "type": "string",
                        "description": "Optional Slack incoming webhook URL. Kept secret by Apify input UI."
                    },
                    "discordWebhookUrl": {
                        "title": "Discord webhook URL",
                        "type": "string",
                        "description": "Optional Discord webhook URL. Kept secret by Apify input UI."
                    },
                    "alertTopLimit": {
                        "title": "Top changes in alert",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "Maximum number of top delta rows included in the Slack/Discord alert summary.",
                        "default": 5
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
