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

Monitor public Shopify products, variant prices and availability. Track price cuts, restocks, new products and confirmed removals with persistent snapshots.

- **URL**: https://apify.com/huggable_chipmunk/shopify-change-tracker.md
- **Developed by:** [Marco Schwartz](https://apify.com/huggable_chipmunk) (community)
- **Categories:** E-commerce, Business
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 product observations

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Price & Stock Change Tracker

Extract public Shopify products and variant prices, then monitor price cuts, price increases, restocks, out-of-stock changes, new products and confirmed catalogue removals. Persistent snapshots make scheduled runs useful for competitor research and ecommerce monitoring.

No store admin access, private Shopify token, proxy subscription, or AI service is required. Only storefront data is read.

### Quick start

1. Enter Shopify store homepages or specific /products/handle URLs.
2. Set a maximum number of products per store.
3. Run the Actor to create a baseline and export JSON, CSV or Excel.
4. Save an Apify Task and schedule it. Enable Only changes to hide unchanged observations on subsequent runs.

```json
{
  "storeUrls": ["https://www.allbirds.com/"],
  "maxProductsPerStore": 100,
  "changesOnly": false,
  "includeDescription": false,
  "monitorId": "competitor-watch"
}
```

For selected products, supply their actual storefront URLs. Product URLs are merged by store. If a store homepage and individual products from that store are both supplied, the full-catalogue scan takes precedence. A monitor scans up to 25 input URLs and up to 5,000 products per store.

### Output

Each product observation includes storeUrl, productId, handle, title, vendor, productType, tags, productUrl, imageUrl, publishedAt, currency, priceMin, priceMax, available, variants, optional description, changeType, changes, previous, and checkedAt.

Variants include stable variantId, title, SKU, decimal price, compareAtPrice and public availability. previous contains prior currency, price range, availability and variants, so individual price/stock changes can be inspected. JSON is best for nested variant history; the overview table gives flat prices and observation types.

Public availability is true when any variant is available, false when every variant explicitly says unavailable, and null when unknown. Currency is taken from the storefront's public cart.js currency field when available, otherwise null. Private inventory quantities are not returned or inferred. Prices are published storefront prices; discounts, shipping and checkout totals are not calculated.

#### Monitoring states

| changeType | Meaning |
| --- | --- |
| baseline | First observation; does not mean newly launched |
| new | Product newly observed since a previous successful scan |
| changed | Published product fields changed |
| unchanged | Same observed fields |
| possibly_removed | Missing from one complete successful catalogue scan |
| removed | Missing from two complete successful catalogue scans |
| returned | Previously removed product appeared again |

changes may contain price_decrease, price_increase, restocked, out_of_stock, compare_at_price_changed, variants_added, variants_removed, currency_changed or metadata_changed. Price comparisons match stable variant IDs. A currency change suppresses price-increase/decrease labels to avoid comparing different currencies.

Removal observations retain the last observed product details. They indicate absence from the public feed, not a confirmed business decision or physical stock count. Missing selected-product endpoints are treated as errors and preserve state; removal confirmation relies on successful whole-catalogue scans.

Snapshots are isolated by running user and monitor name. Without an explicit name, the Task ID or normalized input targets determine the monitor. Use one schedule per monitor; concurrent runs can race. Detected snapshot conflicts skip the update and appear in RUN_SUMMARY. State is subject to Apify's storage retention; an expired snapshot restarts the baseline.

Failed stores preserve snapshots. Capped scans never remove unseen products. If the spending limit prevents full output for a store, that store's snapshot is not advanced, so unreturned changes remain available on a subsequent run. Changing includeDescription does not change comparison fingerprints.

### Pricing

**$5 per 1,000 emitted product observations** ($0.005 each), across all Apify plans. Variants are included in a product record without a separate per-variant event. Baseline, unchanged, changed and removal observations are billable. Only changes reduces output after the first baseline. Failed stores and RUN_SUMMARY do not have an Actor event charge.

Configure Maximum total charge before running. Product output stops at the event budget. Ordinary Apify platform usage charges may apply according to your plan. Store pricing is authoritative.

### Coverage and limitations

- Requires public Shopify products.json or product-handle Ajax .js endpoints. The Ajax endpoint provides selected-product availability, with integer subunit prices converted to decimal prices. Password-protected stores, blocked feeds and non-Shopify websites are reported as errors.
- Homepages and /products/handle URLs are supported. Collection URLs, country/language subpaths, custom API filters, authentication and proxy routing are not supported in this release.
- Catalogue pagination uses a consistent page size. Exactly reaching a configured cap is conservatively marked truncated unless the end of the feed was observed.
- Stock, prices and currency reflect the public response from the run's network location. Storefront personalization and regional pricing can differ from a customer's checkout.
- The first run reports baseline rather than claiming every product is new.
- Fetch size, timeout, retries and public-network validation are bounded. No login, anti-bot bypass, or private admin API is used.
- RUN_SUMMARY records errors, scan truncation, spending-limit status, counts and detected state conflicts. A run fails when all requested stores fail.

### Privacy and support

Only public product data is collected. The currency check reads the currency field from a fresh unauthenticated cart response; cart contents are not stored. Output and snapshots stay in the running user's Apify storage. No external AI or analytics service receives them. Use the Actor's Issues tab for support with a public store URL and run ID, without credentials.

### Local development

Use Node.js 22 or newer: npm ci, npm test, then npm start with input in Apify local storage. Dependencies are pinned. Input/output/dataset schemas are included in .actor. The release script uses APIFY_TOKEN from the environment, never a source-code token.

# Actor input Schema

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

Public store homepages or /products/handle URLs. Up to 25 URLs. Collections and regional subpaths are not supported.

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

Products, not variants. Capped scans never mark unseen products as removed.

## `changesOnly` (type: `boolean`):

Hide unchanged records after the baseline run.

## `includeDescription` (type: `boolean`):

Include the public product description in output. This does not affect comparison snapshots.

## `monitorId` (type: `string`):

Reuse the name to preserve history. Run one schedule per monitor.

## Actor input object example

```json
{
  "storeUrls": [
    "https://www.allbirds.com/"
  ],
  "maxProductsPerStore": 500,
  "changesOnly": false,
  "includeDescription": false,
  "monitorId": ""
}
```

# Actor output Schema

## `results` (type: `string`):

Normalized public records. The dataset schema describes each field.

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

Scan coverage, output counts, errors and spending-limit status.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("huggable_chipmunk/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 = {}

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,huggable_chipmunk/shopify-change-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/UPKUBLFcRhgSHopJZ/builds/PypoqXllqnq7Oregq/openapi.json
