# Shopify Sales Tracker — See What Competitors Actually Sell (`dev_web_col/shopify-sales-tracker`) Actor

Shopify price monitoring and inventory tracking for competitor research: sell-outs, stock drops, price cuts and new product tests since your last run.

- **URL**: https://apify.com/dev\_web\_col/shopify-sales-tracker.md
- **Developed by:** [Diseño Web de Colombia](https://apify.com/dev_web_col) (community)
- **Categories:** E-commerce, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 change detecteds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Sales Tracker — See What Competitors Actually Sell

**Product lists tell you what a store offers. Sell-outs tell you what it sells.**

### What is the Shopify Sales Tracker?

This Actor watches any Shopify store and reports what changed since your last run: products that sold out, variants that dropped stock, prices that were cut, and new products being tested.

Anyone can dump a store's catalogue. The catalogue does not tell you what is working. A variant going out of stock does, and so does a price cut on a product that is not moving.

### Why the diff is the signal

Shopify stores expose their catalogue publicly at `/products.json`. Reading it once gives you a list. Reading it repeatedly and comparing gives you demand.

This Actor keeps a compressed snapshot in a named key-value store in **your own account** and returns only the delta, typed by what it means: `sold-out`, `stock-drop`, `price-cut`, `price-rise`, `new-product`, `removed`.

The first run is a baseline — it does not charge per result and returns a small sample, because billing you for an entire initial catalogue would be an unpleasant first invoice.

### What you can use it for

| What you want | How to ask for it |
|---|---|
| **Price monitoring** — competitor pricing moves | `storeDomains`, read `price-cut` and `price-rise` |
| **Inventory tracking** — what is running out | Read `stock-drop` and `sold-out` changes |
| **Product research** — what actually sells | Sell-out speed is the demand signal |
| **Dropshipping and sourcing** | Spot winners before they are obvious |
| **New product detection** | Read `new-product` changes |
| **Discount cadence** — when does this brand promote? | Schedule daily, chart `price-cut` frequency |
| **Supplier intelligence** — when a stockist runs low | Watch their stock levels |
| **Assortment comparison** | Several `storeDomains` at once |

Typical jobs: **price monitoring**, **inventory tracking**, **competitor
monitoring** for ecommerce, and product research for sourcing.

### What data you get

For each change: the change type, product title, variant, the old and new value, price, currency, stock level where exposed, product URL, image, vendor and product type. Plus the timestamp of the run that detected it.

### Input

Every field is optional unless marked required.

| Field | Type | Description |
|---|---|---|
| `oneShot` | boolean | Return the CURRENT products instead of what changed. Use this for a single lookup or from an AI agent — the monitor needs two runs before it has anything to compare. It never touches your saved history. |
| `storeDomains` | array, **required** | The stores you want to spy on. Just the domain: gymshark.com, mystore.com. The platform is detected automatically — Shopify and WooCommerce both work. This actor watches the stores you choose; it does not discover stores. |
| `proxyConfiguration` | object | Required. Shopify blocks datacenter IPs, including Apify's, so runs without a residential proxy return nothing. Pick Apify Proxy with the RESIDENTIAL group. |
| `monitorKey` | string | Keep this the same across runs — it is how the actor remembers what it already saw. Use a different name for an independent watchlist. |
| `trackSignals` | array | Leave empty to get everything. Sold out, stock drop and new review are the real demand signals — they mean someone bought. |
| `titleKeyword` | string | Only watch products whose title contains this. Leave empty to watch the whole catalogue. |
| `minPrice` | integer | Ignore products cheaper than this, in the store's own currency. |
| `maxPrice` | integer | Ignore products more expensive than this, in the store's own currency. |
| `maxChanges` | integer | Safety cap. You are charged per change returned. |
| `resetBaseline` | boolean | Forget everything seen before and take a fresh baseline. The baseline run is never charged per result. |

#### Input sample

```json
{
  "storeDomains": [
    "gymshark.com",
    "allbirds.com"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

### Output sample

One real row from an actual run:

```json
{
  "changeType": "baseline",
  "signals": [],
  "detectedAt": "2026-08-03T02:40:13.457Z",
  "variantsSold": null,
  "previousMinPrice": null,
  "priceChangePct": null,
  "previousAvailableVariants": null,
  "previousReviewCount": null,
  "id": "gymshark.com:6806953033930",
  "platform": "shopify",
  "storeDomain": "gymshark.com",
  "productId": "6806953033930",
  "handle": "gymshark-everyday-seamless-zip-tracktop-jackets-outerwear-grey-aw26",
  "title": "Gymshark Everyday Seamless Zip Tracktop - Onyx Grey",
  "vendor": "Gymshark | Be a visionary.",
  "productType": "Womens Jackets / Outerwear",
  "tags": [
    "06/08/26",
    "30/7/26-everyday-seamless",
    "activity:Conditioning",
    "... 46 more"
  ],
  "minPrice": 42,
  "maxPrice": 42,
  "compareAtPrice": null,
  "totalVariants": 7,
  "availableVariants": 7,
  "lowStockRemaining": null,
  "reviewCount": null,
  "imageUrl": "https://cdn.shopify.com/s/files/1/0156/6146/files/EverydaySeamlessZipTracktopGSOnyxGreyB1B7P_GB7N_4180.jpg?v=1784724702",
  "url": "https://gymshark.com/products/gymshark-everyday-seamless-zip-tracktop-jackets-outerwear-grey-aw26",
  "publishedAt": "2026-07-30T10:50:00-07:00",
  "updatedAt": "2026-08-02T19:39:14-07:00"
}
```

### Who uses this

- **Ecommerce operators** — see what a competitor is actually selling, not just listing
- **Dropshippers and sourcing agents** — spot winning products by sell-out speed
- **Brand analysts** — track pricing strategy and discount cadence over time
- **Suppliers** — know when a stockist is running low
- **Investors** — demand signals on DTC brands without asking them

### Honest limits

These are real and none of them is fixable by any tool. They are here so you know what you are buying before you run it.

- **A residential proxy is required.** Shopify blocks datacenter IPs. Measured: the same code read 291 products from a laptop and zero from the cloud until residential proxying was turned on.
- **The first run is a baseline** and returns only a sample. Real change detection starts on the second run.
- **Only Shopify stores.** WooCommerce, Magento and custom carts are not covered.
- **Stock numbers are only as good as the store exposes.** Many stores publish availability but not exact quantities, in which case a sell-out is visible but a stock drop is not.
- **A change between two runs is invisible.** If a product sells out and is restocked overnight and you run daily, you will not see it. Schedule more often if timing matters.

### FAQ

#### Do I need permission from the store?

No. The `/products.json` endpoint is public by design — Shopify publishes it so storefronts and apps can read the catalogue. This Actor reads only that public data.

#### Why did my first run return almost nothing?

It is the baseline. There is nothing to compare against yet, so it records the current catalogue and returns a small sample without charging per result. Changes appear from the second run onwards.

#### How does it know something sold out rather than being deleted?

A sold-out variant is still in the catalogue with availability false. A removed product is gone from the feed entirely. They are reported as different change types.

#### How often should I run it?

Daily catches most pricing and stock moves. Hourly makes sense for fast-moving stores or drops. Cost scales with changes found, not with how often you check.

#### Can I watch several stores at once?

Yes, pass a list of domains. Each store keeps its own snapshot under your monitor key.

#### Where is my history stored?

In a named key-value store in your own Apify account. It never leaves your account, and separate monitor keys keep separate histories.

#### Do I need an account or an API key for the source?

No. This Actor only reads public pages and public endpoints, the same ones any
logged-out visitor sees. You never give it credentials, and nothing is done on
your behalf.

#### Is it legal to scrape this data?

Scraping publicly available information is broadly accepted as legal, and this
Actor only ever touches pages that require no login. That said, what you may do
with the data afterwards is a separate question — personal data in particular is
regulated by GDPR and CCPA. If you plan to process personal data, take advice
first. Apify has a good primer: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

#### How much will a run cost me?

You are charged per result, so the cost scales with what you actually get back.
The pricing is shown on this page above the input form. Start with a small run to
see real numbers before you scale up.

#### Can I export to Excel, CSV or Google Sheets?

Yes. Every run's dataset can be downloaded as CSV, Excel, JSON, XML or HTML from
the **Storage** tab, and Apify integrates directly with Google Sheets, Airtable,
Zapier, Make and Slack.

#### Can I run this on a schedule?

Yes. Open the **Schedules** tab and pick an interval — hourly, daily, weekly.
Each run only costs you what it returns.

#### Can I call it from my own code instead of the console?

Yes. Every Actor on Apify is also an API endpoint. There are official clients for
[Python](https://docs.apify.com/api/client/python/) and
[JavaScript](https://docs.apify.com/api/client/js/), plus a plain REST API. The
**API** tab on this page shows ready-made snippets with your input already filled in.

#### Something came back empty. Is it broken?

Usually not. An empty result normally means the filters were too narrow, or the
source genuinely has nothing to return for that query. This Actor is written to
finish successfully and tell you what happened rather than fail — check the run
log, it says which step returned nothing.

### Related Actors

- **Company Signals** — competitor changes beyond the storefront
- **Company Enrichment** — turn a domain into firmographics and contacts

### Where the data comes from

The public `/products.json` endpoint that Shopify stores publish for their own storefronts. Snapshots are kept in your own Apify account.

# Actor input Schema

## `oneShot` (type: `boolean`):

Return the CURRENT products instead of what changed. Use this for a single lookup or from an AI agent — the monitor needs two runs before it has anything to compare. It never touches your saved history.

## `storeDomains` (type: `array`):

The stores you want to spy on. Just the domain: gymshark.com, mystore.com. The platform is detected automatically — Shopify and WooCommerce both work. This actor watches the stores you choose; it does not discover stores.

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

Required. Shopify blocks datacenter IPs, including Apify's, so runs without a residential proxy return nothing. Pick Apify Proxy with the RESIDENTIAL group.

## `monitorKey` (type: `string`):

Keep this the same across runs — it is how the actor remembers what it already saw. Use a different name for an independent watchlist.

## `trackSignals` (type: `array`):

Leave empty to get everything. Sold out, stock drop and new review are the real demand signals — they mean someone bought.

## `titleKeyword` (type: `string`):

Only watch products whose title contains this. Leave empty to watch the whole catalogue.

## `minPrice` (type: `integer`):

Ignore products cheaper than this, in the store's own currency.

## `maxPrice` (type: `integer`):

Ignore products more expensive than this, in the store's own currency.

## `maxChanges` (type: `integer`):

Safety cap. You are charged per change returned.

## `resetBaseline` (type: `boolean`):

Forget everything seen before and take a fresh baseline. The baseline run is never charged per result.

## Actor input object example

```json
{
  "oneShot": false,
  "storeDomains": [
    "gymshark.com",
    "allbirds.com"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "monitorKey": "default",
  "trackSignals": [],
  "maxChanges": 5000,
  "resetBaseline": false
}
```

# Actor output Schema

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

One dataset item per product that changed.

# 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 = {
    "storeDomains": [
        "gymshark.com",
        "allbirds.com"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("dev_web_col/shopify-sales-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 = {
    "storeDomains": [
        "gymshark.com",
        "allbirds.com",
    ],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("dev_web_col/shopify-sales-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 '{
  "storeDomains": [
    "gymshark.com",
    "allbirds.com"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call dev_web_col/shopify-sales-tracker --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

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