Shopify Variant Availability & Price Evidence Monitor avatar

Shopify Variant Availability & Price Evidence Monitor

Pricing

$5.00 / 1,000 successful product checks

Go to Apify Store
Shopify Variant Availability & Price Evidence Monitor

Shopify Variant Availability & Price Evidence Monitor

Check if selected Shopify variants (size, color) are in stock or sold out, and save the raw price as evidence. Restock and competitor variant watch. $0.005 per product check; blocked, failed or unknown checks are free. No login, proxy or browser.

Pricing

$5.00 / 1,000 successful product checks

Rating

0.0

(0)

Developer

LatentLark

LatentLark

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

9 hours ago

Last modified

Features

Limited permissions

Share

Check whether specific Shopify variants (a size, a color) are in stock or sold out on a public storefront, and save the price Shopify returned as timestamped evidence. Paste a product URL and a variant ID and click Start. You get one clear row per variant, and sold out is never confused with blocked, failed or unknown.

No login, no cookies, no proxy, no browser. It reads only Shopify's documented public product endpoint.

Built and maintained by LatentLark. Want the rows in a spreadsheet? Send every run to Google Sheets with Google Sheets Export & Import (No OAuth).

Quick start (first run in under a minute)

  1. Click Try for free (or Start in Console). The form is prefilled with a real product on Shopify's public Dawn theme demo store: the Thelma sandal, variant 39576998346841 (Black / 35).
  2. Click Start. The run takes a few seconds and gives you 1 row in the Output tab, for $0.005.
  3. Replace the URL and variant ID with the products you want to watch, up to 5 products and 20 variants per run.
  4. To be told what changed, click Save as task and add a Schedule (for example, daily). Each run of a task compares against the earlier runs of that same task. A one-off run reports initial_observation.

Finding a variant ID: open the product page, pick the size or color, and copy the number after ?variant= in the address bar. You can also open https://STORE/products/HANDLE.js and look at variants[].id.

What you can do with it

  • Restock watch: see when a sold-out size or color becomes buyable again (availability_changed from out_of_stock to in_stock).
  • Competitor variant availability: track which sizes or colors a competitor has run out of, and when they come back.
  • Ad and campaign QA: label each variant with the ad or campaign it belongs to (label), so you know when an advertised variant is no longer buyable.
  • Price evidence snapshots: keep a dated record of the raw price integer Shopify returned for each variant, with the exact source URL and HTTP status.

Example: the prefilled demo

Input (this is the form prefill):

{
"watchlist": [
{
"productUrl": "https://theme-dawn-demo.myshopify.com/products/thelma-sandal",
"variantId": "39576998346841",
"label": "dawn-demo-thelma-sandal-black-35"
}
]
}

Real output row from a platform run on 9 November 2026 (some fields shortened):

{
"label": "dawn-demo-thelma-sandal-black-35",
"productUrl": "https://theme-dawn-demo.myshopify.com/products/thelma-sandal",
"sourceUrl": "https://theme-dawn-demo.myshopify.com/products/thelma-sandal.js",
"productHandle": "thelma-sandal",
"productId": "6920720777305",
"variantId": "39576998346841",
"variantTitle": "Black / 35",
"availability": "out_of_stock",
"previousAvailability": null,
"event": "initial_observation",
"priceMinor": 38500,
"currency": null,
"currencyStatus": "unknown",
"quantity": null,
"httpStatus": 200,
"variantCoverage": "complete",
"returnedVariantCount": 42,
"baselineWrite": "appended",
"charged": true,
"chargeEvent": "successful-product-check",
"chargeScope": "availability_only",
"requestsUsed": 2,
"requestLimit": 12,
"limitations": ["currency_unknown", "currency_endpoint_disallowed_by_robots"],
"checkedAt": "2026-11-09T18:16:38.035Z"
}

The Black / 35 variant really is sold out on that demo store, while other variants of the same product are in stock. Results on a live demo can change over time.

Pricing (pay per event)

EventPrice
Successful product check$0.005 per product ($5 per 1,000)
Actor startnone
  • One charge per product, not per variant. It covers every variant you selected on that product (up to 20 in total per run).
  • Charged only when every selected variant on the product was classified: in_stock, out_of_stock, variant_not_found or removed.
  • Free: blocked, rate-limited, failed (404, 5xx), unsupported (password page), truncated, timed-out or unknown results. If one selected variant of a product is unknown, that whole product is free.
  • Availability check, not a price check. Most stores don't expose currency to this read-only method (see Limitations). The price integer is saved as evidence, but you pay for the availability classification.
  • Cheap to run: our 1-product test run used about $0.0003 of Apify platform usage in roughly 4 seconds at 256 MB. Example: checking 5 products once a day for 30 days costs 150 × $0.005 = $0.75 in events.

Input

FieldRequiredWhat it does
watchlistyesList of { productUrl, variantId, label?, locale? }. Duplicate product and variant pairs are merged.
watchlist[].productUrlyesHTTPS Shopify product URL, for example https://store.com/products/handle. Any ?variant= in the URL is ignored.
watchlist[].variantIdyesNumeric Shopify variant ID, as a string.
watchlist[].labelnoYour own name for the row (an ad, campaign or SKU). It is never sent to the store.
watchlist[].localenoURL locale prefix such as en or en-ca. It does not simulate a shopper's country.
previousSnapshotnoPaste OUTPUT.snapshot from an earlier run to compare against it without using a task.
stateScopenoSnapshot scope name for local (non-Apify) runs. On Apify, use a saved task or previousSnapshot for history. A task's own ID always takes priority.
maxProductsnoLower the product cap (1–5, default 5).
maxVariantsnoLower the variant cap (1–20, default 20).
maxRequestsnoLower the HTTP request cap (1–12, default 12).
timeoutSecondsnoLower the time budget (5–60 seconds, default 60).

Output

Dataset: one row per selected variant, including unchanged and failed checks. Main fields:

FieldMeaning
availabilityin_stock, out_of_stock, variant_not_found, removed, truncated, blocked, rate_limited, unsupported, http_error or unknown
eventinitial_observation, unchanged, availability_changed, price_changed, currency_changed, variant_not_found, removal_confirmed, truncated or unknown
previousAvailability, previousPriceMinorValues from the last good check of the same task or scope
priceMinor, compareAtPriceMinorPrice integers exactly as Shopify returned them, not divided or converted
currency, currencyStatus, currencySourceThe currency code only when a documented field supplied it. Otherwise null / unknown
quantityAlways null. This Actor does not report unit counts.
httpStatus, reason, sourceUrlWhere the evidence came from, and why a check failed
variantCoverage, returnedVariantCountWhether the product JSON listed all of the product's variants (Shopify lists at most 250)
baselinePreserved, baselineWriteWhether an error left the earlier good result untouched, and whether this run's snapshot was saved
charged, chargeReason, chargeScopeWhether this product was billed, and why or why not
label, labels, checkedAt, limitationsYour label, the check time, and any caveats

Key-value store OUTPUT: a run summary with counts per availability and event, requests used, the caps applied, the charges made, and snapshot, which you can pass as previousSnapshot next time.

Limits

CapMaximum
Unique products per run5
Selected variants per run20
HTTP requests per run (robots.txt, product, redirects, one retry)12
Run time60 seconds
Memory256 MB

If an input is over a cap, the run stops before sending any request and nothing is charged. Requests to each store are limited to 1 per second, with at most 1 retry. Proxies and notifications are not supported, and the run refuses them.

How it works

  • It reads only GET /{locale}/products/{handle}.js, Shopify's documented Ajax product endpoint, and respects each store's robots.txt.
  • out_of_stock is reported only when Shopify returns available: false for that exact variant. A 403, a 404, a timeout or a password page is never recorded as sold out.
  • A variant missing from a complete product document is variant_not_found the first time and removed only after two consecutive complete checks.
  • Errors never overwrite the earlier good result. Each run appends its own snapshot and never rewrites an older one.
  • There are no cart actions, no Storefront or Admin API tokens, and no browser.

Limitations

  • Currency is often unknown. The product JSON has no currency field. Shopify's documented place to read it (/cart.js) is disallowed by many stores' robots.txt, including Shopify's theme demos, and this Actor respects that. In those cases currency is null and price_changed is not emitted, because a price can't be compared safely without a currency.
  • At most 250 variants per product. Shopify's product JSON stops at 250. A selected variant that isn't in a 250-variant response is reported as truncated (unknown), not sold out.
  • Overlapping runs may duplicate events. If two runs of the same task overlap, both can report the same availability_changed. Schedule runs far enough apart that one finishes before the next starts (a run usually takes seconds).
  • History needs a task or previousSnapshot. One-off runs only report initial_observation. After more than 50 stored snapshots in one task, that task's history is no longer trusted; pass previousSnapshot from a recent run instead.
  • No stock counts and no country simulation. quantity is always null, and locale is only a URL prefix.
  • Only public storefronts are supported. Password-protected stores and non-Shopify sites return unsupported or blocked, free of charge. Only monitor stores you are allowed to check.

FAQ

I got blocked or http_error. Was I charged? No. Only fully classified products are charged. Check that the URL is a public /products/... page and that the store's robots.txt allows /products/.

Why is currency null? The store doesn't expose currency to this read-only method, or its robots.txt disallows /cart.js. The raw priceMinor is still saved.

Why don't I see availability_changed? The first run of a task, or a one-off run, is always initial_observation. Save the input as a task and schedule it, or pass previousSnapshot.

variant_not_found but the product exists? Check the variant ID (it's the number after ?variant=). A variant is only marked removed after two consecutive complete checks without it.

Can I watch 100 products? Not in one run. The limit is 5 products and 20 variants per run, which keeps every run fast and cheap. Use several tasks for more.

Does it tell me how many units are left? No. available: false means the storefront isn't selling that variant right now. It isn't a unit count.

More LatentLark Actors