# Shopify Price & Stock Change Tracker (`fried_calamaries/shopify-change-tracker`) Actor

Monitor any Shopify store for changes — price increases/decreases, back-in-stock & out-of-stock flips, and products added or removed. Run on a schedule for set-and-forget competitor and supplier watching.

- **URL**: https://apify.com/fried\_calamaries/shopify-change-tracker.md
- **Developed by:** [ByteMe](https://apify.com/fried_calamaries) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.01 / change detected

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 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 Change Tracker

### Pain points

- Manually re-checking competitor or supplier stores for price and stock changes is tedious and easy to miss.
- A one-time scrape tells you today's prices, not what actually changed since last time.
- Spotting restocks, sell-outs, and new products across many stores by hand doesn't scale.

### What we solve

- Diffs a Shopify store's public catalog against the previous run — one row per real change.
- Catches price moves (old → new, %), back-in-stock / out-of-stock flips, and products added or removed.
- Point it at competitors, suppliers, or your own stores and run it on a schedule.
- First run is a free baseline; pay only per change, empty runs free.

### Summary

Watch a list of Shopify stores and get told exactly what changed since last time. Each run reads the store's public catalog and diffs it against the previous run, so you get one row per real change: a price moved (with the old price, new price, and % change), a product went out of stock or came back, or a product was added or removed. The first run captures a baseline; every run after that is pure signal — point it at competitors, suppliers, or your own stores, put it on a daily schedule, and turn price/stock monitoring into a set-and-forget task. Built for dropshippers, repricing teams, and competitive-intelligence analysts.

### Who it's for

- Dropshippers and resellers watching supplier catalogs
- Repricing and merchandising teams tracking competitor prices
- Competitive-intelligence analysts monitoring DTC brands
- Buyers watching for restocks and new drops

### How to use

Set the input, run the actor, and collect results from the run's dataset (export to JSON/CSV/Excel, or pull via the Apify API). Example input:

```json
{
  "domains": [
    "allbirds.com",
    "colourpop.com"
  ],
  "minPriceChangePercent": 0
}
````

See **Inputs** below for every available field.

### What you get

One row per record:

| Field | Description |
|---|---|
| `domain` | Store domain monitored |
| `change_type` | price\_increased, price\_decreased, back\_in\_stock, out\_of\_stock, new\_product, removed\_product (or a free baseline/snapshot/unavailable marker) |
| `product_title / product_handle` | The product that changed |
| `variant_sku / variant_id` | The specific variant, for price/availability changes |
| `old_price / new_price` | Price before and after the change |
| `price_change_pct` | Signed percentage price change |
| `old_available / new_available` | Stock status before and after the change |
| `tracked_products` | Products tracked this run (on heartbeat rows) |
| `changes_found` | Number of changes detected this run (on the snapshot heartbeat row) |
| `detected_at` | UTC timestamp the change was detected |
| `source_url` | The store URL |

Sample:

```json
{
  "domain": "allbirds.com",
  "change_type": "price_decreased",
  "product_title": "Wool Runner",
  "product_handle": "wool-runner",
  "product_id": 100,
  "variant_sku": "WR-9-GREY",
  "variant_id": 1001,
  "old_price": 110.0,
  "new_price": 88.0,
  "price_change_pct": -20.0,
  "old_available": null,
  "new_available": null,
  "tracked_products": null,
  "changes_found": null,
  "detected_at": "2026-02-01T00:00:00+00:00",
  "source_url": "https://allbirds.com"
}
```

### Inputs

| Field | Required | Type | Default | Description |
|---|---|---|---|---|
| `domains` | yes | array | `["allbirds.com"]` | Shopify store domains or URLs to monitor, e.g. 'allbirds.com'. The first run captures a baseline (free); run again later (a schedule works well) to get the changes since the previous run. |
| `minPriceChangePercent` | no | integer | `0` | Ignore price moves smaller than this percentage (noise filter). 0 reports every price change. |
| `maxProductsPerStore` | no | integer | `2000` | Cap on products sampled per store (bounds cost). Very large catalogs are sampled up to this many products. |
| `proxyConfiguration` | no | object | `{"useApifyProxy": false}` | Optional. Shopify storefronts are usually reachable directly; enable a proxy (e.g. residential) only if a store is blocked. |

### Pricing (Pay Per Event)

You pay per result (`dataset-item`) — **no charge for empty runs**. Example: **1000 changes detected** at *$0.01/result* ≈ **$10.00**.

The first run for a store is a free baseline, and runs with no changes cost nothing — you're only charged per detected change. Apify platform usage (compute) is billed separately per your plan.

### Use cases

- Competitor price monitoring — repricing teams get alerted when a rival raises, drops, or discounts a price.
- Restock / sell-out alerts — buyers and merchandisers know when a hot product returns or sells out.
- New-product watch — analysts catch every product a store adds or removes, for trend-spotting.
- Supplier monitoring — dropshippers track supplier catalogs for price and availability shifts that hit margins.

### Why this actor

- Diffs the catalog between runs — you get what changed, not another full snapshot.
- Catches price moves, stock flips, and product add/remove per SKU.
- First run is a free baseline; pay only per change.

### Limitations & updates

Public storefront `/products.json` only — never real inventory counts, sales, revenue, or orders (those are Admin-API-only). Diffing needs a prior run, so the first run for each store is a baseline with no changes. ~10–15% of stores disable `/products.json` (those return an 'unavailable' marker). Availability reflects the storefront's per-variant `available` flag. Some stores sit behind bot protection — enable the residential proxy toggle if a run is blocked.

### FAQ

**How does it detect changes?**

It reads the store's public catalog (/products.json) and diffs it against the previous run's snapshot.

**What happens on the first run?**

It captures a free baseline — there's nothing to diff yet. From the second run on, you get the changes.

**How am I charged?**

Pay-per-change: one charge per detected change. Runs with no changes are free.

**What changes does it catch?**

Price increases/decreases (with old price, new price, and %), back-in-stock and out-of-stock flips, and products added or removed.

**How often should I run it?**

On a schedule (e.g. daily) — it's built for set-and-forget monitoring.

**Are there store limits?**

\~10–15% of stores disable /products.json; those return an 'unavailable' marker. Enable the proxy toggle if a store blocks datacenter IPs.

### Which actor to choose

Part of the same Shopify-intel suite — pick the one that fits your goal:

- **Shopify Price & Stock Change Tracker** *(this actor)* — monitor stores over time for price moves, restocks, and catalog changes (run on a schedule).
- **Shopify Store Audit & Tech-Stack Lead Scorer** — audit a store right now — installed apps, theme, tech-stack gaps, and catalog signals — for B2B prospecting.

# Actor input Schema

## `domains` (type: `array`):

Shopify store domains or URLs to monitor, e.g. 'allbirds.com'. The first run captures a baseline (free); run again later (a schedule works well) to get the changes since the previous run.

## `minPriceChangePercent` (type: `integer`):

Ignore price moves smaller than this percentage (noise filter). 0 reports every price change.

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

Cap on products sampled per store (bounds cost). Very large catalogs are sampled up to this many products.

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

Optional. Shopify storefronts are usually reachable directly; enable a proxy (e.g. residential) only if a store is blocked.

## Actor input object example

```json
{
  "domains": [
    "allbirds.com",
    "colourpop.com"
  ],
  "minPriceChangePercent": 0,
  "maxProductsPerStore": 2000,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Per-store changes since the last run: price increases/decreases, back-in-stock / out-of-stock flips, and products added/removed.

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

// Run the Actor and wait for it to finish
const run = await client.actor("fried_calamaries/shopify-change-tracker").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 = { "domains": ["allbirds.com"] }

# Run the Actor and wait for it to finish
run = client.actor("fried_calamaries/shopify-change-tracker").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 '{
  "domains": [
    "allbirds.com"
  ]
}' |
apify call fried_calamaries/shopify-change-tracker --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Shopify Price & Stock Change Tracker",
        "description": "Monitor any Shopify store for changes — price increases/decreases, back-in-stock & out-of-stock flips, and products added or removed. Run on a schedule for set-and-forget competitor and supplier watching.",
        "version": "0.1",
        "x-build-id": "UdB1whHYOakLPsyAm"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/fried_calamaries~shopify-change-tracker/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-fried_calamaries-shopify-change-tracker",
                "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/fried_calamaries~shopify-change-tracker/runs": {
            "post": {
                "operationId": "runs-sync-fried_calamaries-shopify-change-tracker",
                "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/fried_calamaries~shopify-change-tracker/run-sync": {
            "post": {
                "operationId": "run-sync-fried_calamaries-shopify-change-tracker",
                "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": [
                    "domains"
                ],
                "properties": {
                    "domains": {
                        "title": "Store domains",
                        "type": "array",
                        "description": "Shopify store domains or URLs to monitor, e.g. 'allbirds.com'. The first run captures a baseline (free); run again later (a schedule works well) to get the changes since the previous run.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "minPriceChangePercent": {
                        "title": "Min price change %",
                        "minimum": 0,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Ignore price moves smaller than this percentage (noise filter). 0 reports every price change.",
                        "default": 0
                    },
                    "maxProductsPerStore": {
                        "title": "Max products per store",
                        "minimum": 1,
                        "maximum": 25000,
                        "type": "integer",
                        "description": "Cap on products sampled per store (bounds cost). Very large catalogs are sampled up to this many products.",
                        "default": 2000
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Optional. Shopify storefronts are usually reachable directly; enable a proxy (e.g. residential) only if a store is blocked.",
                        "default": {
                            "useApifyProxy": false
                        }
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
