# Shopify Store Tracker: Product, Price & Stock Monitor (`deanko/shopify-store-tracker`) Actor

Track any Shopify store's products per variant: new launches, price drops, discounts, restocks and removals, with Slack or Discord alerts. No login or API key.

- **URL**: https://apify.com/deanko/shopify-store-tracker.md
- **Developed by:** [dean ko](https://apify.com/deanko) (community)
- **Categories:** E-commerce, Marketing, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $30.00 / 1,000 100 products scanneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Shopify Store Tracker: Product, Price & Stock Monitor

**Shopify Store Tracker** watches any Shopify store and tells you what changed since the last run, **per variant**: new product launches, price drops, price increases, discounts, back-in-stock, out-of-stock and removed products. It works as a **Shopify product scraper** on the first run (you get the full catalog right away) and as a **Shopify price tracker and store monitor** on every run after that. Put it on a schedule and get the changes in **Slack, Discord or any webhook**.

No login, no Shopify API key and no browser. It reads the store's public product catalog (`/products.json`), so it is fast and cheap.

### What does Shopify Store Tracker do?

- Scrapes every product and variant of a Shopify store, or of one collection: title, vendor, product type, tags, SKU, price, compare-at price, discount %, availability, image and URL.
- Saves the catalog in your Apify account and, on the next run, compares the store with it.
- Labels every variant with an event: `first_seen`, `new_product`, `price_drop`, `price_increase`, `back_in_stock`, `out_of_stock`, `removed` or `no_change`.
- Sends one alert message per run to Slack, Discord or any webhook for new products, restocks and price drops above your threshold.

#### Who is it for?

- **E-commerce brands and DTC teams** doing competitor monitoring on rival Shopify stores.
- **Dropshippers and resellers** who want to know when a supplier adds products, changes prices or runs out of stock.
- **Deal hunters and sneaker/beauty fans** who want restock and sale alerts from their favorite stores.
- **Analysts and agencies** who need a daily catalog and price history of Shopify stores in a spreadsheet or database.

#### Use cases

- **Competitor price monitoring**: see every price change a competitor makes, with the old price, the new price and the % change.
- **New product alerts**: get a Slack or Discord message when a brand drops a new product or collection.
- **Discount and sale tracking**: `compareAtPrice` and `discountPercent` show what is on sale and by how much.
- **Restock alerts**: know when sold-out sizes or colors are back in stock.
- **Catalog export**: one row per variant, ready for Google Sheets, Excel, BI tools or your own database.

### Why use this Shopify store tracker?

- **You get data on the first run.** The first run outputs the whole catalog (every variant as `first_seen`), so you can use it as a plain Shopify scraper too. Some monitors return nothing until the second run.
- **One row per variant, not per product.** Prices and stock are tracked per size or color, so a single sold-out size is not hidden inside a product row.
- **Alerts built in.** Paste a Slack or Discord webhook URL and you are done. No Zapier, Make or n8n needed (but they work too: the webhook body also has the full `alerts` array).
- **Track a whole store or just one collection**, for example only `/collections/sale` or only a brand's new arrivals.
- **Discounts out of the box**: `discountPercent` is computed from the store's compare-at price.
- **Failures are free and isolated.** A store that is not Shopify or blocks the request gets one `error_not_shopify` / `error_blocked` row and is skipped without charge; the other stores still run.
- **Handles big stores.** Pages are streamed, so stores with tens of thousands of variants fit in memory. Shopify's per-IP rate limits are handled by rotating Apify Proxy IPs (on by default), or by automatic waits and retries if you turn the proxy off.
- **Cost control.** Cap products per store, or set a maximum spend per run; the Actor stops cleanly when the budget is used.

### How to use Shopify Store Tracker

1. Open the Actor and click **Try for free**.
2. In **Shopify stores or collection URLs**, add one or more stores: a domain (`allbirds.com`), a store URL, or a collection URL (`https://store.com/collections/sale`).
3. (Optional) Paste a **Slack or Discord webhook URL** and set the **price drop threshold** for alerts.
4. Click **Start**. The first run saves the current catalog; every variant is marked `first_seen`.
5. Create a **Schedule** (Actor page → Schedules), for example every 6 or 24 hours. Each run compares the store with the previous run and reports only real changes as events.
6. Turn on **Output only changes** if you only want changed rows in the dataset.

#### Example input

```json
{
  "storeUrls": [
    "kyliecosmetics.com",
    "https://www.allbirds.com/collections/womens-socks"
  ],
  "trackerName": "competitors",
  "dropThresholdPercent": 10,
  "webhookUrl": "https://hooks.slack.com/services/XXX/YYY/ZZZ",
  "onlyChanges": true,
  "maxProductsPerStore": 1000,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

The default input tracks one small collection (`https://kyliecosmetics.com/collections/kylie-fragrance`, about 50 variants), so a test run costs about $0.03.

### Sample output

One row per variant. Example of a price drop:

```json
{
  "store": "kyliecosmetics.com",
  "event": "price_drop",
  "alert": true,
  "productId": 9262920302834,
  "variantId": 50085820989682,
  "handle": "cosmic-kylie-jenner-2-0-50ml-pen-spray-duo-gift-set",
  "title": "Cosmic Kylie Jenner 2.0 50ml & Pen Spray Duo Gift Set",
  "variantTitle": null,
  "vendor": "kylie-fragrance",
  "productType": "Set",
  "tags": ["back in stock", "Brand_Principles:vegan"],
  "sku": "KF202",
  "price": 66,
  "previousPrice": 80,
  "changePercent": -17.5,
  "compareAtPrice": 80,
  "discountPercent": 17.5,
  "available": true,
  "createdAt": "2026-09-14T13:20:03-07:00",
  "publishedAt": "2026-10-08T09:46:52-07:00",
  "updatedAt": "2026-10-17T04:31:19-07:00",
  "url": "https://kyliecosmetics.com/products/cosmic-kylie-jenner-2-0-50ml-pen-spray-duo-gift-set?variant=50085820989682",
  "image": "https://cdn.shopify.com/s/files/...jpg",
  "checkedAt": "2026-10-17T11:30:18.513Z"
}
```

| Field | Description |
|---|---|
| `store` | Store domain, or `domain/collections/handle` when you track a collection |
| `event` | What happened to this variant since the last run (see the table below) |
| `alert` | `true` if this row was included in the webhook alert |
| `productId`, `variantId`, `handle` | Shopify IDs and product handle |
| `title`, `variantTitle` | Product name and variant name (size, color…); `null` for single-variant products |
| `vendor`, `productType`, `tags` | Catalog metadata set by the store |
| `sku` | Variant SKU, if the store sets one |
| `price`, `previousPrice`, `changePercent` | Current price, price on the last run, and % change |
| `compareAtPrice`, `discountPercent` | "Was" price set by the store and the resulting discount % |
| `available` | Whether the variant can be bought right now |
| `createdAt`, `publishedAt`, `updatedAt` | Timestamps from Shopify |
| `url`, `image` | Direct variant link and image URL |
| `checkedAt` | When this run checked the store |
| `error` | Only on `error_not_shopify` / `error_blocked` rows: why the store was skipped |

The dataset has two views: **Changes** (event, prices, stock, link) and **All variants** (every field).

#### Events

| event | meaning | alert |
|---|---|---|
| `first_seen` | first run for this store and tracker name | no |
| `new_product` | product or variant that did not exist on the last run | yes |
| `price_drop` | price went down (`changePercent` is negative) | if the drop is at least your threshold |
| `price_increase` | price went up | no |
| `back_in_stock` | unavailable on the last run, available now | yes |
| `out_of_stock` | available on the last run, unavailable now | no |
| `removed` | variant was in the store on the last run but is gone now | no |
| `no_change` | nothing changed | no |

#### Webhook alerts

If a run finds alerts, one JSON POST is sent to your webhook with `text` (shown by Slack), `content` (shown by Discord) and the full `alerts` array (for Zapier, Make, n8n or your own endpoint). New products are listed once per product, not once per variant.

### Pricing

This Actor uses pay-per-event pricing. You pay **$0.03 per 100 product variants scanned** (event `products-scanned-100`), counted per store and rounded up, plus a tiny start fee of $0.00005 per run. You pay for scanning, not for output rows.

**Worked example:** a store with 693 variants = 7 events = **$0.21 per run**. Checking it once a day for 30 days costs about **$6.30 per month**. Tracking just one collection of 56 variants = 1 event = **$0.03 per run**.

- **Output only changes** does not change the price; it only keeps your dataset small.
- Stores that fail (blocked or not Shopify) are not charged.
- Use **Max products per store** to cap the cost of very large stores, or set a maximum cost per run in the run options; the Actor scans only what that budget covers and then stops.

### Integrations and API

Run the Actor and read results from your own code with the Apify API client. Replace `<YOUR_APIFY_TOKEN>` with your token from Apify Console → Settings → API & Integrations.

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("deanko/shopify-store-tracker").call(run_input={
    "storeUrls": ["kyliecosmetics.com"],
    "trackerName": "competitors",
    "onlyChanges": True,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["event"], item.get("title"), item.get("price"), item.get("previousPrice"))
```

**JavaScript / Node.js**

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('deanko/shopify-store-tracker').call({
    storeUrls: ['kyliecosmetics.com'],
    trackerName: 'competitors',
    onlyChanges: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) console.log(item.event, item.title, item.price, item.previousPrice);
```

You can also:

- Export the dataset as **JSON, CSV, Excel, XML or HTML** from the run page or the API.
- Connect it to **Google Sheets, Make, Zapier, n8n, Slack** and more through Apify integrations.
- Run it on a **Schedule** and fetch the latest dataset with the "last run" API endpoint.

### FAQ

**How do I monitor a competitor's Shopify store for price changes?**
Add the store's domain, run once to save a baseline, then schedule the Actor (for example daily). Every later run labels each variant `price_drop`, `price_increase`, `no_change` and so on, with `previousPrice` and `changePercent`.

**Can I use it just to scrape all products from a Shopify store?**
Yes. The first run outputs every variant of the store as `first_seen` with prices, SKUs, stock status, images and URLs.

**How do I know if a site is a Shopify store?**
Just add it. If the store has no public Shopify catalog, you get a free `error_not_shopify` row and it is skipped.

**Why is a store reported as `error_blocked`?**
Some stores sit behind Cloudflare or other bot protection, are password protected, or rate-limit requests. Switch the proxy to the Residential group and run again. Password-protected stores cannot be read.

**Where is the previous-run data stored? How do I reset it?**
In a named key-value store called `shopify-store-tracker` in your Apify account, one record per tracker name and store. To start fresh, use a new **Tracker name** or delete the record.

**Can I track several watchlists separately?**
Yes. Use a different **Tracker name** for each watchlist (for example per client); their histories never mix.

**How often can I run it?**
As often as you like. Every 6 to 24 hours is typical for competitor monitoring; restock alerts work better with shorter intervals.

**Does it get inventory quantities?**
No. It reports whether each variant is available (`available: true/false`), not how many units are left.

### Limitations

- Only products published to the store's Online Store channel are visible. Draft, hidden, wholesale-only and password-protected products are not returned.
- Prices are in the store's default currency; the currency code is not included in the output.
- Inventory quantities are not available, only in-stock / out-of-stock per variant.
- If a store has more products than **Max products per store**, only the first N are tracked and `removed` detection is turned off for that store (products past the cap would otherwise look removed).
- If a store starts blocking halfway through a run, the variants already scanned are kept and saved, and `removed` detection is skipped for that run.
- Shopify rate-limits its public catalog per IP. With the proxy on (default) the Actor rotates IPs; with it off, it waits and retries, so very large stores (5,000+ products) can take several minutes.
- Works only on Shopify. WooCommerce, BigCommerce, Magento, Amazon and other platforms are not supported.

### Legal

Only public product data is collected; no personal data. You are responsible for using the data in line with the store's terms and applicable laws.

### Support and feedback

Found a bug, a store that does not work, or missing a field? Open an issue in the **Issues** tab of this Actor's page. Feature requests and feedback are welcome there too.

# Actor input Schema

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

Shopify stores to track. Enter a domain (allbirds.com), a store URL (https://www.allbirds.com) or a collection URL (https://kyliecosmetics.com/collections/kylie-fragrance) to track only that collection. Sites that are not Shopify are reported in the dataset and skipped without charge.

## `trackerName` (type: `string`):

The last run's catalog is saved per tracker name and store in your account, and each run is compared with it. Use different names for independent watchlists. A new name starts fresh: every variant is reported as first_seen.

## `dropThresholdPercent` (type: `integer`):

A price drop triggers an alert only if it is at least this many percent. New products and back-in-stock variants always trigger an alert. Set 0 to alert on any drop.

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

Optional. If a run finds alerts, one JSON POST is sent here with `text` (for Slack), `content` (for Discord) and the full `alerts` array (for Zapier, Make, n8n or your own API).

## `onlyChanges` (type: `boolean`):

If on, variants that did not change since the last run are not written to the dataset. The first run still outputs every variant as first_seen. Scanned variants are charged either way.

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

Stop after this many products per store to cap the cost of big catalogs (one product can have many variants). 0 = no limit. If a store has more products than this, removed-product detection is turned off for it.

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

On by default: Apify Proxy rotates IPs so Shopify's per-IP rate limit (HTTP 429) does not slow runs down. For stores reported as error_blocked (Cloudflare or bot protection), switch to the Residential proxy group.

## Actor input object example

```json
{
  "storeUrls": [
    "https://kyliecosmetics.com/collections/kylie-fragrance"
  ],
  "trackerName": "default",
  "dropThresholdPercent": 5,
  "onlyChanges": false,
  "maxProductsPerStore": 500,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

## `all` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "storeUrls": [
        "https://kyliecosmetics.com/collections/kylie-fragrance"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("deanko/shopify-store-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 = {
    "storeUrls": ["https://kyliecosmetics.com/collections/kylie-fragrance"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("deanko/shopify-store-tracker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "storeUrls": [
    "https://kyliecosmetics.com/collections/kylie-fragrance"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call deanko/shopify-store-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,deanko/shopify-store-tracker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/qzsdS4G96BULFklvs/builds/ojdE5vf9FfkKly58L/openapi.json
