Shopify Competitor Change Monitor avatar

Shopify Competitor Change Monitor

Pricing

$15.00 / 1,000 successful store snapshots

Go to Apify Store
Shopify Competitor Change Monitor

Shopify Competitor Change Monitor

Monitor public Shopify stores for new products, promotions, stock changes, and other meaningful catalog activity. See prioritized changes after the first run.

Pricing

$15.00 / 1,000 successful store snapshots

Rating

0.0

(0)

Developer

Kibira

Kibira

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

See what's changing in a competitor's Shopify catalog, including new products, promotions, restocks, and price moves. Run it again anytime to check for what's new.

What does Shopify Competitor Change Monitor do?

This Actor watches one or more public Shopify stores and tells you what's changed since the last time you checked. Give it a list of store web addresses. It checks each store's public product catalog, remembers what it saw, and reports what's different on every run after that: new or removed products, promotions starting or ending, items going in or out of stock, price moves, and more. Each result is tagged with an importance level, so you can focus on what matters most.

It only reads what a store already shows to any visitor: the same public catalog page a browser or another shopper can load. No login or private account access is required, and it doesn't collect customer data. It only works with Shopify stores.

Because it runs on Apify, you also get scheduling, an API, dataset export, and run history built in. There's no separate tool to set up.

What can you use it for?

  • Competitor catalog monitoring: Keep a running record of what's changing in a competitor's store, all in one place.
  • New product monitoring: Catch new items as soon as they're listed.
  • Promotion and sale monitoring: See when a competitor starts or ends a discount.
  • Stock and restock monitoring: Know when popular items sell out or come back.
  • Price change tracking: Get notified when a price goes up or down.

How to get started

  1. Open the Actor and enter the store web addresses you want to watch (for example, https://allbirds.com).
  2. Run it. This first run doesn't report changes yet: it's building a starting point. See What happens on the first run below.
  3. Run it again later, either by hand or on an Apify schedule, using the same store list. Every run after the first compares what it finds against what it saw last time and reports what changed.
  4. Open the Dataset tab to see the results, or download them as JSON, CSV, Excel, and more.

What happens on the first run

The first time you check a store, there's nothing to compare against yet, so this run builds a starting point rather than reporting changes. It will never claim a price just changed or an item just sold out on this first run, since there's no earlier state to compare against.

What it can tell you right away, just from how the catalog looks today:

  • Recently published products: Anything the store listed in the last 7 days.
  • Advertised discounts: Products currently priced below the store's own listed reference price. This first run can't confirm a sale is genuinely underway, since there's no earlier price to compare against yet. It only reports what the catalog shows today.

If 30% or more of a store's products show an advertised discount, that's reported as a single widespread advertised discounts summary instead of hundreds of individual rows. Many stores use a standing reference price across most of their catalog, and one summary is more useful than a wall of near-identical results.

Everything else about the catalog is saved quietly so the next run can compare against it.

What happens on later runs

Every run after the first compares the current catalog against what was saved last time and reports genuine changes, including:

  • New products or products that were removed
  • New product options (sizes, colors, etc.) or options that were removed
  • Items going out of stock or coming back in stock (an item has to have been in stock for at least 14 days first, so normal pre-launch stock wobble on a brand-new item isn't mistaken for a stockout)
  • Promotions (sales) starting or ending
  • Price increases or decreases
  • A product's advertised discount changing with no change to the actual price
  • Old listings reappearing (a sign a product may have been reactivated rather than being genuinely new)

To keep results useful rather than noisy:

  • When several things happen to the same product at once (say, a price drop and a stockout), they're reported together as one result with the details attached, instead of several separate rows.
  • When a large share of a store's products (30% or more) change price in the same run, that's reported as a single store-wide price change instead of flooding the Dataset with individual rows.

Understanding priorities

Every result is tagged with an importance level: High, Medium, or Low. This lets you tell at a glance what's most likely to matter.

  • High: A promotion starting, a store-wide price change, or a price move of 15% or more.
  • Medium: A promotion ending, an item going out of stock, a newly published product, or a new or removed product.
  • Low: Everything else, including smaller price moves, restocks, new or removed product options, possible relists, and discount-only changes.

Choose the minimum importance level you want to see in the Dataset. The setting is called minPriority. Set it to Medium or High to cut down on noise. This only affects what's shown; it never changes what the Actor collects or remembers, so you can change it later without losing anything.

Understanding your results

Each run adds rows to the Dataset tab. Every row tells you which store it's about, what happened, how important it is, and a link straight to the product on the live store so you can see it for yourself. The Dataset tab's default Overview shows just these plain-language columns; switch to the Details / technical view there if you need the underlying record types and exact field names.

Here's a real result, captured from a live run against allbirds.com. It's a product with an advertised discount:

{
"store": "allbirds.com",
"productTitle": "Trino® Tubers - Navy Night",
"eventLabel": "Advertised discount",
"priority": "MEDIUM",
"variantTitle": "S (W5-7)",
"discountLabel": "75% off",
"evidenceUrl": "https://allbirds.com/products/trino-tubers-navy-night?variant=31338069262480"
}

You don't need any technical background to read this: the store, the product, what happened, how important it is, and a link to check it yourself. The Technical information section below documents the exact machine-readable field names (signalType, percentOffCompareAt, etc.) and every record type in full, for anyone integrating with the Dataset programmatically.

Pricing

You're charged $0.015 each time the Actor successfully checks a store and saves its results. If a store can't be reached or fails to load, you're not charged for that store. There's no extra fee based on how many products a store has, and no extra fee based on how many changes are found.

Your actual monthly cost depends on how many stores you watch and how often you check them. There's no flat subscription fee. For example:

UsageApproximate monthly cost
1 store, checked daily≈ $0.45
5 stores, checked daily≈ $2.25
10 stores, checked daily≈ $4.50
25 stores, checked daily≈ $11.25
50 stores, checked daily≈ $22.50
100 stores, checked daily≈ $45.00

Checking weekly instead of daily costs roughly a seventh as much. These are illustrative examples, not guaranteed totals. Your bill reflects your actual usage.

Limitations and data handling

  • Shopify stores only. It reads a Shopify store's public product catalog; it doesn't work with other e-commerce platforms.
  • Public data only. It reads only what the store already shows to any visitor. It never logs in, never bypasses a password or login page, and never accesses a store's admin area or customer accounts. It doesn't collect personal or customer data of any kind.
  • No history before you start. The first run can't know about changes that happened before you started watching a store. See What happens on the first run for details.
  • Not real-time. It reports what changed between the runs you schedule. It doesn't watch continuously in the background, so it can't guarantee catching every change (for example, something that changed and then changed back between two runs).
  • Fixed rules for now. Thresholds like the 7-day "recently published" window and the 30%-of-catalog store-wide trigger are fixed at this stage and aren't user-configurable, aside from the minPriority setting above.

Technical information

Input reference

FieldTypeRequiredDescription
storeUrlsarray of stringsYesStore web addresses to watch, up to 10 per run (e.g. "https://allbirds.com" or "gymshark.com").
maxProductsPerStoreintegerNoOptional limit on how many products are checked per store. Useful for testing or keeping costs predictable. Leave empty to check every product.
minPriorityLOW | MEDIUM | HIGHNo (default LOW)The minimum importance level to include in the Dataset. See Understanding priorities above.

See the Input tab for the full schema with inline descriptions.

Dataset record types

Every pushed row has a recordType field identifying which of five record families it belongs to, following one hierarchy: store-level → product-level → variant-level detail.

The record types below that describe a signal or change also carry a few additive, display-only fields for the Dataset's default Overview view: eventLabel (a plain-English rendering of signalType/primaryType/type) and discountLabel/priceChangeLabel (plain-English renderings of percentOffCompareAt/percentChange/medianPercentMove/affectedPercent, for example "75% off" or "18% decrease"). These are additive: they never replace or change the machine-readable fields, which you should use for anything programmatic.

store_summary: One per store per run, always present. Reports whether the check succeeded, how many products and variants were found, and whether this was the first run (snapshotStatus: "baseline_created") or a comparison run ("baseline_updated").

classified_baseline_signal: First run only. A current-state observation (recently published, or an advertised discount against the store's own reference price), never a historical change. signalType: "currently_on_sale" is the machine-readable value behind the "Advertised discount" label; the name is kept for compatibility with existing integrations, but the label was changed because Run 1 has no earlier price to compare against, so it can't confirm a genuine sale is underway.

classified_baseline_rollup: First run only, and only when 30% or more of a store's products show an advertised discount in the same run. Replaces those individual classified_baseline_signal rows with one store-level summary (eventLabel: "Widespread advertised discounts"), so a store with a widespread reference-pricing pattern doesn't flood the Dataset with hundreds of near-identical rows. Reports affectedProductCount, totalProductCount, and affectedPercent so you can see exactly how much of the catalog was affected. The per-product facts behind it aren't destroyed: they're independently visible on the store's own public product pages, and they're recomputed fresh on every run.

Real example, captured from a live run:

{
"recordType": "classified_baseline_rollup",
"store": "taylorstitch.com",
"type": "widespread_advertised_discount",
"eventLabel": "Widespread advertised discounts",
"priority": "MEDIUM",
"affectedProductCount": 2647,
"totalProductCount": 3813,
"affectedPercent": 69.42,
"discountLabel": "69.42% of catalog"
}

classified_change: Later runs only. One prioritized, product-level result. evidence lists any other classifications folded into it, and variantEvidence preserves every underlying variant's own numbers when more than one contributed.

Illustrative example (field shapes are real and tested; this specific event wasn't captured live during development):

{
"recordType": "classified_change",
"store": "example-store.com",
"productTitle": "Trail Runner - Charcoal",
"primaryType": "sale_started",
"eventLabel": "Sale started",
"priority": "HIGH",
"evidence": [],
"variantTitle": "US 10",
"percentChange": -25,
"priceChangeLabel": "25% decrease",
"evidenceUrl": "https://example-store.com/products/trail-runner-charcoal?variant=123"
}

classified_sitewide_change: Later runs only, and only when 30% or more of active products moved price in one run.

{
"recordType": "classified_sitewide_change",
"store": "example-store.com",
"type": "sitewide_price_change",
"eventLabel": "Store-wide price change",
"priority": "HIGH",
"affectedProductCount": 42,
"medianPercentMove": -18.5,
"priceChangeLabel": "18.5% decrease"
}

Local development

npm install
npm run build
npm run start:dev # runs src/main.ts directly via tsx, using local storage/
npm test # vitest

Local runs read input from storage/key_value_stores/default/INPUT.json and write to the local storage/ directory, which is not synced to Apify Cloud. Use a real Apify run to verify Cloud behavior. See AGENTS.md for the project's engineering rules and frozen product decisions.