Shopify Stores API Velocity, Pricing & Brand Model avatar

Shopify Stores API Velocity, Pricing & Brand Model

Pricing

from $21.00 / 1,000 stores

Go to Apify Store
Shopify Stores API Velocity, Pricing & Brand Model

Shopify Stores API Velocity, Pricing & Brand Model

Analyse any Shopify store from its public catalog: launch velocity in products per day, price positioning, discount strategy and brand model.

Pricing

from $21.00 / 1,000 stores

Rating

0.0

(0)

Developer

Spool

Spool

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

Share

Shopify Stores API — Velocity, Pricing & Brand Model

Give it a Shopify store. Find out how fast it ships, what it charges, how hard it discounts, and whether it's an own brand or a reseller.

kith.com 5.4 new/day 5.6 published/day $1,611 active luxury
gymshark.com 0.0 new/day 15.8 published/day $18 republishing budget
finisterre.com 1.9 new/day 3.3 published/day $137 steady mid-market
allbirds.com 0.0 new/day 0.1 published/day $115 dormant mid-market

Gymshark and Allbirds both created zero new products in the last 90 days. One is re-merchandising its catalog sixteen times a day; the other has genuinely gone quiet. Every tool that reads one date tells you those two stores are the same.

Every Shopify store publishes its whole catalog at /products.json — no key, no login, permitted by robots.txt. Each product carries the date it went live, which means a store's growth rate is readable from a single request.


Two dates, two different businesses

Every Shopify product carries created_at and published_at, and almost everything built on this endpoint picks one and hopes.

published_at is rewritten in bulk whenever a store replatforms or rebuilds its theme. Allbirds spans 7.6 years by created_at and 83 days by published_at — a decade of catalog stamped with one afternoon in June. Deriving a launch rate from it is wrong in both directions at once:

from published_at measured properly error
allbirds.com 3.54/day 0.00/day infinite
gymshark.com 12.39/day 0.00/day infinite
finisterre.com 0.28/day 1.86/day 6.6x too low
rothys.com 0.22/day 0.81/day 3.7x too low
deathwishcoffee.com 0.03/day 0.14/day 4.7x too low

Wrong on every store tested — overstating dead ones by an unbounded factor and understating live ones several-fold.

So both rates are reported. perDay counts products genuinely created in the last 90 days; publishPerDay counts what the store published in the same window. The gap between them is the finding:

new/daypublished/dayreading
gymshark.com0.015.8republishing — re-merchandising, very much alive
allbirds.com0.00.1dormant — actually winding down
kith.com26.427.8constant — genuinely shipping new product

It tells you when it doesn't know

A 90-day window only works if the read reached back 90 days, and on a fast store it doesn't. Kith reads 2.8/day at 250 products, 10.9 at 1,000 and 26.4 at 2,500 — still climbing.

Most tools present that as fact. This one flags it. velocityConfidence comes back low, and because truncation can only ever hide recent products and never invent them, perDay is then a lower bound rather than a wrong number.

It is not a blanket disclaimer — it fires only when it should:

organicbasics.com 250 products → 1.76/day high full catalog → 1.77/day
finisterre.com 250 products → 1.86/day high full catalog → 1.86/day
rothys.com 250 products → 0.81/day high full catalog → 0.81/day
kith.com 2,500 products → 26.4/day low still rising

Organic Basics called correctly to within 0.6% from a default read, while Kith — the one case that genuinely can't be resolved cheaply — says so. publishPerDay gets the same treatment, with an exact test rather than an estimated one.


Detecting a replatform, and why the obvious test fails

catalogRepublished is worth filtering on by itself: a store that just migrated is a store currently buying apps, themes and agency time.

Getting it right took three attempts. Comparing the created span against the published span returned true for every store tested at 250 products — including Rothy's, Organic Basics and Finisterre, whose complete reads prove they were never republished. The busiest-publish-day share failed the same way. Both collapse for one reason: the catalog is paged newest-published-first, so any truncated read looks compressed in publish time no matter what the store did.

What survives is the lag between a product being created and being published, because that is a property of each product rather than of the read window:

lag @250 @500 @2500 verdict
finisterre.com 36d 37d 39d normal
rothys.com 55d 50d 41d normal
kith.com 1.8d 1.8d 1.9d normal
allbirds.com 596d 559d — republished
gymshark.com 697d 724d 136d republished

Stores publishing normally measure 2–106 days; stores that rewrote their catalog measure 136–724. The verdict is now identical at every read depth for all eight test stores — it was wrong for five of them before.


Which apps the store pays for

The catalog tells you what a store sells. The storefront tells you how it operates — and that is the part an app developer or agency buys.

organicbasics.com 9 apps Klaviyo · Judge.me · Yotpo · Narvar · ShopMy · Klarna
deathwishcoffee.com 8 apps Klaviyo · Postscript · Rebuy · Smile.io · Afterpay
finisterre.com 7 apps Okendo · Gorgias · Klevu · AB Tasty · Elevar · Klarna
rothys.com 2 apps Intelligems · Yotpo

Over 50 apps are recognised across email/SMS, reviews, support, subscriptions, CRO, loyalty, search, analytics, post-purchase, payments and affiliate — each labelled with its category. Anything third-party that cannot be named is still reported in otherThirdPartyHosts, so a store running something unusual shows up rather than looking simpler than it is.

Set requireApps and it becomes a lead list: every store running Klaviyo but not Recharge is one run.

The theme comes with it, and themeIsStock flags the free Shopify themes. A store still on stock Dawn has not invested in design — which separates a real operation from a side project more reliably than catalog size does.


Prices you can actually compare

products.json carries prices as bare numbers with no currency anywhere in it. A UK store showing 115 and a US store showing 115 are £115 and $115, and a yen-priced store looks like luxury goods at about a hundred dollars.

So the currency is read from the store profile and every price is reported twice — in the store's own currency and in USD:

finisterre.com GBP median £102 → $137.01 mid-market
organicbasics.com EUR median €41 → $46.60 mid-market
allbirds.com USD median $115 → $115 mid-market

Price positioning is judged on the USD figure, never the raw number — reading Finisterre's 102 as dollars drops it a whole bracket, and a yen-priced store would read as budget goods. When a rate is unavailable the USD fields are left null rather than filled with a guess.


Quick start

{ "storeUrls": ["allbirds.com", "kith.com", "rothys.com"] }

Domains, full URLs and bare handles all work. www. is stripped, and www.x.com and x.com are merged so you're never billed twice for one store.


What you get back

{
"store": "finisterre.com",
"storeName": "Finisterre",
"country": "GB",
"city": "St Agnes",
"currency": "GBP",
"shipsToCountryCount": 39,
"productsSampled": 500,
"catalogComplete": false,
"perDay": 1.86,
"velocityConfidence": "high",
"publishPerDay": 3.33,
"publishConfidence": "high",
"velocitySample": 167,
"velocityWindowDays": 90,
"newestAt": "2026-09-14T15:41:10.000Z",
"catalogRepublished": false,
"medianPublishLagDays": 37.05,
"republishShare": 0.08,
"priceMin": 6, "priceMedian": 102.5, "priceMax": 295,
"priceMedianUsd": 137.01,
"onSaleShare": 0.12, "averageMarkdown": 0.35,
"outOfStockShare": 0.1,
"vendorCount": 1,
"topVendors": [{ "name": "Finisterre", "count": 500 }],
"productTypes": [{ "name": "Men's Jackets", "count": 41 }],
"theme": "LinedUp / BFVA",
"themeIsStock": false,
"appCount": 7,
"apps": ["AB Tasty", "Back in Stock (Amp)", "Elevar", "Klarna", "Klevu", "Okendo"],
"appsByCategory": { "reviews": ["Okendo"], "support": ["Gorgias"], "cro": ["AB Tasty"] },
"socialChannels": ["instagram", "facebook", "youtube"],
"signals": {
"launchCadence": "steady",
"pricePositioning": "premium",
"discountStrategy": "occasional",
"brandModel": "own-brand",
"catalogScale": "mid",
"inventoryPressure": "normal"
}
}

signals carries the reading; every threshold is published in signals.thresholds, so you can disagree with an interpretation without losing the numbers behind it.

Six dataset views ship with it: Overview, Apps & tech, Growth, Pricing, Catalog and Unavailable.


Recipes — copy, paste, run

Which of my competitors is actually shipping?

{ "storeUrls": ["rival-one.com", "rival-two.com", "rival-three.com"] }

Find the resellers in a list — who stocks other people's brands

{
"storeUrls": ["store-a.com", "store-b.com"],
"requireSignals": ["brandModel:multi-brand-reseller"]
}

Stores in trouble — heavy discounting and empty shelves

{
"storeUrls": ["..."],
"requireSignals": ["discountStrategy:permanent-sale", "inventoryPressure:mostly-unavailable"]
}

Stores that just replatformed — buying apps, themes and agency time right now

{
"storeUrls": ["..."],
"requireSignals": ["launchCadence:republishing"]
}

Exact catalog and full price range on a big store

{ "storeUrls": ["gymshark.com"], "maxProductsPerStore": 5000 }

Every option

OptionDefaultWhat it does
storeUrls—Required. Domains, URLs or handles, mixed freely
maxProductsPerStore500How deep to read. The default settles velocity on most stores; when it cannot, velocityConfidence says so. Raise it for an exact catalog count and lifetimePerDay
requireApps(none)Keep only stores running Klaviyo, Recharge, Gorgias… The lead-list filter
requireAppsModeanyall finds a specific stack, like Klaviyo and Recharge
detectAppstrueRead the storefront for apps, theme and socials. One extra request per store
requireSignals(none)Keep only stores matching launchCadence:constant, brandModel:multi-brand-reseller, pricePositioning:luxury…
minProducts0Skip stores smaller than this — filters out test and abandoned shops
includeProductsfalseAdd every product with title, URL, vendor, tags, date and price
maxConcurrency5Stores analysed in parallel

What it covers, honestly

About 5 stores in 6 work. Tested against 18 real stores: 15 served the catalog, 3 did not. Those three return not_a_shopify_store — either they've disabled the endpoint or they're not on Shopify. A miss is always reported, never silent.

Stripping www. matters more than it sounds: three of those stores failed with the www. prefix and succeeded without it, so it's normalised for you.

catalogSize is exact only when catalogComplete is true. On a catalog larger than your read limit, the count is null rather than a number that would be wrong. productsSampled always tells you what was actually read.

Price and discount figures come from the sample, which is the newest end of the catalog. For a complete catalog they're exact; otherwise they describe current stock rather than everything ever sold.

Currency and shipping reach are what the store serves you. Shopify switches storefront by geography, so an Italian brand answered in USD when tested from outside the EU, and reported shipping to 2 countries rather than its full list. The figures are reported exactly as the store gave them rather than normalised into something that looks tidier but is invented.

Availability depends on the store. Some publish it, some don't — stockDataAvailable says which, rather than reporting a misleading zero.

App detection reads what the storefront loads. A large retailer that self-hosts its scripts shows fewer apps than it runs — Gymshark detects only 1 — so a low count on a big brand means "not visible", not "not installed".

No proxy, no key, no blocking. Two or three plain HTTPS requests per store.


When a store can't be read

errorMeaning
not_a_shopify_storeNo public catalog at /products.json — disabled, or not Shopify
catalog_blockedThe store returned 403 or 429
catalog_emptyCatalog exists but has no products
invalid_inputCouldn't read a domain from that value

A breakdown is saved to the key-value store as RUN_SUMMARY.


FAQ

How do I find a Shopify store's product catalog? Pass the domain. The Actor reads the public /products.json endpoint that every Shopify store serves, and returns the catalog plus derived metrics.

How is this different from a product scraper? Product scrapers hand you rows. This measures the store: how fast it ships, where it prices, how it discounts, whether it resells. You can get to a shortlist without reading a single product.

Can it tell me how much a store earns? No, and nothing honestly can from public data. Tools quoting revenue are estimating. This reports what the store itself publishes — catalog, prices, dates, availability — and derives only what those support.

Does it work on any store? Roughly five in six. Some owners disable the public catalog, and those are reported rather than guessed at.

Is this legal? /products.json is a public endpoint Shopify serves by design, it requires no authentication, and robots.txt permits it. Everything returned is catalog data — products, prices, dates. No customer data, no personal information.


How to use it

  1. Open the Actor and paste your store domains into Shopify stores — one per line, www. or not.
  2. Optionally set requireApps (e.g. Klaviyo) or requireSignals (e.g. brandModel:multi-brand-reseller) to turn the scan into a shortlist.
  3. Click Start. Ten stores take about ten seconds.
  4. Open the Growth, Pricing or Apps & tech dataset view, or export the whole thing as CSV, Excel or JSON.
  5. To repeat it weekly, use Schedule; to pull it into your own system, call the run through the API or an integration (Google Sheets, Make, Zapier, webhooks).

How much does it cost?

Pay per event — you are charged per store analysed, and nothing for stores that could not be read.

Planper store
Free$0.03
Bronze$0.027
Silver$0.024
Gold$0.021

A store that was read but filtered out by your requireSignals / minProducts settings costs $0.002. Actor start is $0.002.

Worked examples

  • Analyse 10 competitors → 10 × $0.03 = $0.30
  • Scan 100 Shopify stores for ones running Klaviyo → about $3.00 (Gold plan: $2.10)
  • The free plan's $5 credit covers roughly 160 stores

No proxy is used, so there is no proxy bill on top.


More Shopify tools from spool

All three read the same public endpoints, respect robots.txt, and report a miss rather than guessing.


Support

Open an issue on the Issues tab and you'll get a reply, usually the same day. Requests for extra metrics are welcome — tell me what you need measured.