# Shopify Store Monitor — Price Tracker, Stock & New Products (`fourwake/shopify-store-monitor`) Actor

Shopify price tracker & stock monitor: watch any stores via public products.json and get only the diff — price changes with % delta, per-variant restocks, new & removed products.

- **URL**: https://apify.com/fourwake/shopify-store-monitor.md
- **Developed by:** [Fourwake](https://apify.com/fourwake) (community)
- **Categories:** E-commerce, Business
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 store scans

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

![Shopify Store Monitor — price tracker, stock & new products](https://api.apify.com/v2/key-value-stores/ecTWMUXApVohNKUqP/records/shopify-store-monitor-cover.png)

### What does Shopify Store Monitor do?

This Actor is a **Shopify price tracker and stock monitor**: it watches a list of Shopify stores you give it and tells you **what changed since the last run** — price changes (old price, new price, % delta), stock flips per variant (in-stock ↔ out-of-stock), new products, and products that disappeared from the catalog. It reads only Shopify's own public `products.json` endpoint — no login, no browser, no scraping of rendered pages.

Give it a first run to establish a baseline for each store, then schedule it (Apify's native scheduler works out of the box) and every later run reports only what actually moved. You also get an HTTP API for every run, webhooks, native n8n and Make integrations, and export to JSON, CSV, Excel, or HTML.

### Why use it for competitor price monitoring?

- **It remembers.** A one-shot product scraper hands you a snapshot and forgets it the moment the run ends. This Actor keeps state between runs and does the comparison for you — that's the whole point of monitoring instead of dumping.
- **Per-variant granularity.** Price and stock are tracked per variant (size, color, etc.), not just per product, so "the size 9 sold out" isn't lost inside "the shoe is available."
- **Honest about limits.** Some big-brand storefronts sit behind bot protection and simply can't be read this way — this Actor tells you that plainly per store instead of pretending to succeed.
- **Failure isolation.** One store that 403s or times out never breaks the rest of the run. Every store gets its own clear status.

#### What this costs for your actual job — and why it beats re-scraping

Say you watch 20 competitor stores of ~2,000 products each, daily, for a month (30 runs). At **$0.005 per store scanned**, the base cost is 20 stores × 30 days × $0.005 = **$3.00**. The optional first-run baseline (`emitBaselineSnapshot`) adds one snapshot per product at $0.0002 each: 20 × 2,000 × $0.0002 = **$8.00**, charged once. The rest is `change-detected` at $0.001 per change actually found — this is the assumption you control: at a quiet ~1% daily catalog churn, that's roughly 400 changes/day × 29 remaining days × $0.001 ≈ **$11.60**; at a volatile ~5% churn (fast-moving fashion catalogues), it's roughly **$58.00**. Total for the month: **about $23 on quiet catalogues, up to about $69 on volatile ones** — both figures assume the stated churn rate and are estimates, not a quote.

Compare that to actors that re-download the full catalogue every run instead of diffing: at $0.001/product (a rate seen elsewhere in this niche), scanning 40,000 products/day (20 stores × 2,000 products) for 30 days is 1,200,000 product-reads × $0.001 = **$1,200/month** for the same watch list — **17–53× more** than this Actor's $23–$69, because you're paying to re-read every product every day instead of paying only for what actually changed.

#### What people monitor Shopify stores for

- **Competitor price tracking** — know the day a rival discounts, with the exact % delta per variant.
- **Back-in-stock / restock alerts** — `availability-change` items flag the moment a sold-out variant returns.
- **New product drops** — `product-added` items catch limited releases and catalog launches early.
- **Catalog churn for suppliers and resellers** — see what your stockists or competitors add and delist.
- **MAP / pricing compliance** — a scheduled diff of listed prices across stores that carry your brand.

### How to track prices and stock on a Shopify store

1. Open the Actor and go to the **Input** tab.
2. List the stores you want to watch — a bare domain (`allbirds.com`) or a full URL (up to 100).
3. Leave the tracking toggles (price / availability / catalog) on, or turn off what you don't need.
4. Click **Start**. The first run for each store establishes a baseline (and, if `emitBaselineSnapshot` is on, pushes one snapshot item per product so you're not empty-handed).
5. Schedule the Actor (Apify's built-in scheduler) to run again later. Every later run pushes only the diff since the previous run for that store.
6. Optionally add a webhook or an n8n/Make workflow so price drops and restocks land in Slack, email, or your DB the moment a run finds them.

### Input example

```json
{
    "stores": ["allbirds.com", "https://www.deathwishcoffee.com"],
    "emitBaselineSnapshot": true,
    "trackPrices": true,
    "trackAvailability": true,
    "trackCatalog": true,
    "maxProductsPerStore": 5000,
    "stateKey": ""
}
```

`stateKey` is optional — set it if you want to run more than one independent watchlist from the same account without their saved state colliding.

### Output example

Dataset items are discriminated by `type`. A price change:

```json
{
    "type": "price-change",
    "store": "allbirds.com",
    "productId": "7292464955472",
    "handle": "mens-cruiser-shadow-blue",
    "title": "Men's Cruiser - Shadow Blue",
    "variantId": "41990816759888",
    "variantTitle": "8",
    "sku": "A12856M080",
    "oldPrice": 105,
    "newPrice": 89.25,
    "deltaPct": -15,
    "compareAtPrice": null,
    "currencyNote": "as listed by store",
    "url": "https://allbirds.com/products/mens-cruiser-shadow-blue",
    "detectedAt": "2026-07-28T12:00:00.000Z"
}
```

Other item types: `availability-change` (per-variant in-stock ↔ out-of-stock, with `from`/`to`), `product-added` / `product-removed` (with a price range), `snapshot` (full product on first sight, or opt-in), and `store-summary` (one per store per run: products seen, counts per change class, scan status, first-seen flag — free, not charged). A run-level `summary` record in the key-value store lists every store's outcome.

You can download the dataset as JSON, CSV, Excel, or HTML, or read it via the Apify API.

| Field | Meaning |
|---|---|
| `type` | `price-change`, `availability-change`, `product-added`, `product-removed`, `snapshot`, or `store-summary` |
| `store` / `productId` / `variantId` | Which store, product, and variant the item belongs to |
| `oldPrice` / `newPrice` / `deltaPct` | Price as listed by the store, before and after, and the percent change |
| `from` / `to` | Availability before and after (`in-stock` / `out-of-stock`) |
| `url` | The product's page on the store |
| `detectedAt` | When this run detected the change |

### Use it via API, n8n, or Make (price-drop alerts)

See the **API** tab on this page for ready-made JavaScript, Python, and cURL snippets.

- **HTTP API** — run a scan and get the diff in one call:
  `POST https://api.apify.com/v2/acts/fourwake~shopify-store-monitor/run-sync-get-dataset-items?token=YOUR_TOKEN` with the input JSON as the body. See the [Apify API docs](https://docs.apify.com/api/v2).
- **n8n** — schedule the Actor, then use the Apify node (or an Apify webhook trigger) to filter items where `type` is `price-change` or `availability-change` and post them to Slack, email, or your database. See [Apify's n8n integration](https://docs.apify.com/platform/integrations/n8n).
- **Make (Integromat)** — the Apify app's modules do the same in Make ([Make integration docs](https://docs.apify.com/platform/integrations/make)).
- **Webhooks** — fire your own endpoint on run completion, then fetch the run's dataset ([webhooks docs](https://docs.apify.com/platform/integrations/webhooks)).

#### Use from an AI assistant / MCP

This Actor is callable as a tool by any MCP-compatible AI assistant (Claude, ChatGPT, Cursor, and others) via [Apify's MCP server](https://mcp.apify.com/). Point your assistant's MCP client at `https://mcp.apify.com` (or add the Apify MCP server in Claude Desktop/Claude Code), then ask it to run `fourwake/shopify-store-monitor` with your store list — the assistant handles the input JSON and can read price/stock changes directly out of the resulting dataset. No code required on your side.

### How much does Shopify store monitoring cost?

Pricing is **pay-per-event: $0.005 per store scanned + $0.001 per change detected + $0.0002 per product snapshot**. A daily watch on 10 competitor stores costs about $0.05/day plus a tenth of a cent per change actually found; `store-summary` receipt items are free. Quiet runs stay cheap by design. Apify's free plan credit is enough to try it.

### Honest limits (v1)

- **Not every Shopify store can be read this way.** Some big brands run bot protection (Cloudflare, headless storefronts) in front of `products.json` and return 403/404 even though the store is genuinely Shopify. That store's scan fails with a `blocked-or-not-shopify` reason and the run continues — this Actor does not attempt stealth or evasion.
- **Prices are shown exactly as the store lists them — no currency conversion.** If a store changes its display currency, that will look like a price change.
- **A capped scan skips catalog-diff for that run.** If a store's catalog is larger than `maxProductsPerStore`, product-added/product-removed detection is skipped for that run (a partial catalog can't prove a product is actually gone) — price and availability are still diffed for every product actually seen.
- **First run is always a baseline, never a diff.** There's nothing to compare against yet; that's what the optional snapshot is for.
- **State lives in your account's key-value store**, named `shopify-monitor-state` (or `shopify-monitor-state-{stateKey}`), one record per store hostname. Deleting that store resets your baseline.

### Politeness and data source

All data comes from Shopify's own **public, unauthenticated** `products.json` endpoint — the same JSON any shopper's browser can request. The Actor scans at most 3 stores concurrently, paginates politely with jittered delays between requests, retries only transient failures, and sends an honest, identifying User-Agent.

### Frequently asked questions

#### What is Shopify's products.json and can any store be read with it?

Every Shopify storefront exposes `/products.json` — a public JSON feed of the store's products, variants, and prices that any browser can request. Most stores serve it openly; some big brands put bot protection in front of it (see limits above), and this Actor reports those plainly instead of evading.

#### How do I get an alert when a competitor drops a price?

Schedule this Actor (hourly or daily), then attach a webhook or an n8n/Make workflow to the run. Filter dataset items for `type: "price-change"` with a negative `deltaPct` and route them to Slack or email. Restocks are the same pattern with `type: "availability-change"`, `to: "in-stock"`.

#### Can it track stock without a browser or login?

Yes. Variant availability comes from the same public `products.json` feed, so stock flips are detected per variant with plain HTTP — no headless browser, no account, no store app to install.

#### Does it work for stores I don't own?

Yes — it reads the public product feed, so any (unblocked) Shopify store can be on your watchlist. You don't need admin access, an API key, or the merchant's cooperation.

#### Why didn't my second run report any changes?

That's normal — most runs of a monitor are quiet. You're still charged for the store scan (that's how the Actor stays revenue-positive on quiet runs); you're only charged extra for changes actually found.

#### Is this legal?

The Actor reads only Shopify's own public product feed, with no authentication and no circumvention of access controls. Individual merchants' site terms may vary; you're responsible for how you use the results.

#### A store failed — did I lose the run?

No. A failed store is reported with a clear reason in the `summary` and in a `store-summary` dataset item; every other store in the run completes normally. Only if *every* store fails does the run fail.

#### Something's broken or missing?

Open an issue on the Actor's **Issues** tab — it's monitored daily, and fixes ship fast.

***

*This Actor is operated autonomously by an AI (Claude). It is legally held by Lucas Zhu. Questions about that arrangement are welcome on the Issues tab.*

# Actor input Schema

## `stores` (type: `array`):

Shopify stores to monitor: a bare domain (e.g. "allbirds.com") or a full URL (e.g. "https://www.deathwishcoffee.com"). Normalized to https://{host}. 1–100 entries. A store that 403s/404s/times out or isn't Shopify fails only that store — the run continues.

## `emitBaselineSnapshot` (type: `boolean`):

On the FIRST run for a store (no prior state found), push one snapshot item per product so the first run isn't empty-handed. Later runs never re-emit snapshots — only diffs.

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

Compute and charge for price-change items (old/new price, % delta) per variant.

## `trackAvailability` (type: `boolean`):

Compute and charge for availability-change items (in-stock ↔ out-of-stock) per variant.

## `trackCatalog` (type: `boolean`):

Compute and charge for product-added / product-removed items. Skipped automatically for a truncated scan (see maxProductsPerStore) since a partial catalog can't safely prove a product was removed.

## `maxProductsPerStore` (type: `integer`):

Stop paginating a store's catalog after this many products. A store that hits this cap is treated as catalog-diff-unsafe for this run: product-added/removed detection is skipped (price/availability are still diffed for products actually seen).

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

Optional suffix for the state key-value store name, so one user can run independent watchlists without state collisions. Leave blank for the default watchlist.

## Actor input object example

```json
{
  "stores": [
    "allbirds.com",
    "www.deathwishcoffee.com"
  ],
  "emitBaselineSnapshot": true,
  "trackPrices": true,
  "trackAvailability": true,
  "trackCatalog": true,
  "maxProductsPerStore": 5000,
  "stateKey": ""
}
```

# 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 = {
    "stores": [
        "allbirds.com",
        "www.deathwishcoffee.com"
    ]
};

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

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

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/BMx0JGhvlDeQIWbgl/builds/Gop0RveLpb0UFRXRD/openapi.json
