PAL Shopify Catalog & Variant Change Tracker
Pricing
from $2.00 / 1,000 product variant exporteds
PAL Shopify Catalog & Variant Change Tracker
Recheck bounded public product feeds for newly listed, removed, repriced or changed variants. For Shopify operations and migration teams. Check the live Pricing tab and input limits.
Pricing
from $2.00 / 1,000 product variant exporteds
Rating
0.0
(0)
Developer
Practical AI Lab
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Practical AI Lab (PAL) Actor for pricing and market-research teams. It reads the public product feed of up to three Shopify storefronts, produces a clean variant-level dataset, and – when you hand it the previous snapshot – tells you exactly what changed:
- variants added or removed
- price changes (absolute and % delta)
- compare-at price changes
- availability flips (in stock ⇄ sold out)
Store version: production-ready. Pay-per-event pricing is configured; the active plan is listed in the Pricing tab.
Try a real public storefront: the input form is pre-filled with https://www.allbirds.com and a low-cost starter limit of two products, one page. This public feed was reachable during a read-only test on October 24, 2026; availability can change. For a bigger snapshot, increase the product/page limits (up to 200 products per store). This tool is not affiliated with Allbirds or Shopify.
How it works (buyer steps)
- Baseline run – enter 1–3 store URLs (
https://shop.example.com) and run. Every row haschangeType: "baseline". - Open the run's Key-value store and copy the
SNAPSHOTrecord (JSON). - Comparison run (days or weeks later) – same store URLs, paste that JSON into Previous snapshot.
- Download the dataset as JSON or CSV. Filter on
changeType(added,removed,changed,unchanged) andchangeTypes(price_changed|compare_at_price_changed|availability_changed). Tick off Output unchanged variants to get only the differences. - Save the new
SNAPSHOTas the baseline for the next comparison.
RUN_SUMMARY in the same key-value store lists a status per store.
Example input
{"storeUrls": ["https://shop.example.com"],"previousSnapshot": { "schemaVersion": 1, "variants": [ ... ] },"maxProductsPerStore": 200,"emitUnchanged": false}
Example output row (changed)
{"variantKey": "shop.example.com:7001:42001","productKey": "shop.example.com:7001","sourceStore": "shop.example.com","productTitle": "Trail Bottle", "variantTitle": "750 ml", "sku": "TB-750","price": "24.00", "previousPrice": "28.00", "priceDelta": "-4.00", "priceDeltaPercent": -14.29,"compareAtPrice": "28.00", "available": true, "previousAvailable": false,"changeType": "changed", "changeTypes": "price_changed|compare_at_price_changed|availability_changed","currency": null,"productUrl": "https://shop.example.com/products/trail-bottle","variantUrl": "https://shop.example.com/products/trail-bottle?variant=42001"}
Stable keys
variantKey = <store host>:<Shopify product id>:<Shopify variant id>. Keys use Shopify's numeric ids, so renamed titles or handles do not break comparisons. If a merchant deletes and recreates a product, Shopify issues new ids and it will show as removed + added.
Safety behaviour
- Only
https://store roots; reads only/robots.txtand/products.json(GET, no cookies, no login, no checkout, no customer data, no CAPTCHA handling). robots.txtis honoured; a Disallow covering/products.jsonends that store's run. An unreadable robots file (403/429/5xx) also stops it.- HTTP 403, 429, non-JSON or non-Shopify responses stop the store immediately (no retries, no workarounds).
- SSRF protection: hostnames must be public domains; every DNS answer must be a public IP (loopback, private, link-local, reserved, multicast and IPv4-embedding IPv6 ranges are refused); the connection is pinned to the validated IP; redirects are followed only over HTTPS to the same host and re-validated.
- Caps: 3 stores, 200 products/store, 8 pages/store, 5 MB/response, 15 s per request, 90 s and 20 requests per store.
- A store that fails emits no rows and is never charged. Failed stores are never treated as "everything removed".
Limitations – please read
- Availability is a boolean (
available) from the public feed. It is not an inventory count. - Currency is
null. Public/products.jsondoes not reliably expose it; prices are the storefront's numeric amounts (formatted to 2 decimals). Market-specific or discount-code pricing is not reflected. - Max 200 products per store. For larger catalogs the store is
partial_limit, and removed-variant detection is skipped (otherwise unseen products would be reported as removed). - Stores that disable or hide
/products.json, password-protect the storefront, or disallow it in robots.txt cannot be read. Shopify may also return a subset of products on some themes/apps. - Only data published by the store itself is returned; no customer, order or checkout information.
- Comparisons only cover stores present in the supplied snapshot (others are
not_compared). Baseline rows for variants of a store that could not be read are simply left untouched in your own saved copy. - The Actor is not affiliated with Shopify. Use it only on stores and for purposes your legal advice and the store's terms allow.
Output views & schema
Dataset fields are listed in the Variant snapshot & changes view. Per-store statuses: ok, partial_limit, robots_denied, blocked, no_public_feed, non_json, http_error, timeout, network_error, response_too_large, redirect_blocked, blocked_destination, robots_unavailable, request_limit, invalid_url, duplicate, stopped_charge_limit, skipped_charge_limit.
Pricing
Pay-per-event pricing is configured. The Actor charges the event variant-emitted once per successfully emitted current variant row (removed rows, failures and skipped stores are free) and stops cleanly when your run's charge limit is reached. It does nothing at all if that event is not configured.
Development
python3 -m unittest discover -s tests # offline, standard library only