Shopify Store Analyzer — Theme, Apps, Products per Domain avatar

Shopify Store Analyzer — Theme, Apps, Products per Domain

Pricing

$5.00 / 1,000 per store analyzeds

Go to Apify Store
Shopify Store Analyzer — Theme, Apps, Products per Domain

Shopify Store Analyzer — Theme, Apps, Products per Domain

Feed it domains, get one intelligence row per store: is it Shopify (4 detection tiers), theme + version + custom flag, exact product & collection counts, price range, currency, 70+ detectable apps/pixels/payment methods, socials and contact email. No discovery — it analyzes the list you have.

Pricing

$5.00 / 1,000 per store analyzeds

Rating

0.0

(0)

Developer

Scrapers Delight

Scrapers Delight

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 hours ago

Last modified

Share

Shopify Store Analyzer — Theme, Apps & Product Counts per Domain

Feed this Actor the store domains you already hold; it returns one intelligence row per STORE (not per product): isShopify with a 4-tier detection confidence, myshopifyDomain, shopId, themeName, themeVersion, themeIsCustom, productCount, collectionCount, priceMin/priceMax, currency, countryCode, the apps, ad pixels and payment methods detectable from the homepage (70 signatures: 49 apps, 14 pixels, 7 payment methods), socialLinks, and contactEmail where the homepage publishes one. No login, no API key, no browser. No discovery and no crawling beyond the domains you give it — this is the analysis side of the pipe, for lists you already have.

Measured on a real 45-domain mixed list (2026-08-15): 39 billed verdicts — 36 Shopify, 3 correctly identified as not Shopify — and 6 no-verdict domains (4 store-side bot walls, 2 dead) returned as rows but NOT billed. You pay $0.005 only when you get an answer.

{
"domains": ["allbirds.com", "gymshark.com", "colourpop.com", "deathwishcoffee.com",
"stevemadden.com", "kyliecosmetics.com", "fashionnova.com", "ruggable.com"],
"maxProductPages": 8,
"fetchCollections": true
}

Click Try for free and hit Start — that is the input the Actor ships with. A platform run on those shipped defaults returned 8 rows in 35 seconds for $0.04: 8/8 Shopify verdicts including one headless frontend with an open catalog (fashionnova) and one fully headless build (ruggable), each labeled with its detection tier instead of being silently guessed at — and the run log printed its own billing reconciliation: 8 events charged for 8 rows, 1:1.


The wedge: one row per store, and you pick the stores

Nearly every "Shopify scraper" on the Store is a product scraper — you give it one store, it gives you thousands of product rows. This Actor answers a different question: "what is this store?" — asked across a whole list at once. Agencies qualifying a pitch list, app vendors scoring leads by tech stack, and competitive researchers need the store-level row (platform, theme, catalog size, price band, app stack), not 2,000 product rows per domain.

The intelligence comes from three sources no estimate can fake:

  • The Shopify globals every Liquid storefront inlines — Shopify.shop (the myshopify handle), Shopify.theme (name, version, and whether it came from the official theme store), currency, country, locale, shop id.
  • The public catalog API (/products.json, paged at 250/page) — an exact product count on most stores (28 of the 33 counted stores were exact at the default depth), plus real price range, vendors, product types, and newest/oldest product publish dates — a live activity signal.
  • Homepage script signatures — 70 curated app/pixel/payment fingerprints (Klaviyo, Recharge, Rebuy, Gorgias, Attentive, Judge.me, Meta/TikTok/Pinterest pixels, Shop Pay, Afterpay, Klarna…). Measured: 4.5 detected apps per Shopify store on average (max 10).

How this differs from our Shopify App Store Leads Scraper: that Actor walks the Shopify App Store and produces one row per app publisher (support email, developer website, ratings) — it is how you find the sellers of apps. This Actor takes store domains you already hold and analyzes the stores themselves, including which of those apps each store runs. Use them at opposite ends of the same pipeline.


Read this before you buy rows

Five things that would otherwise turn into a refund request.

  1. contactEmail is sparse: 38.9% on the 36-store sample. It is whatever the homepage itself publishes (mailto links first, visible footer text second) — no guessing, no enrichment, no contact-form scraping. If you need an email on every row, pair this with an email finder; do not buy this expecting one.
  2. A verdict is billed even when the answer is "not Shopify." The verdict is the product when you qualify a mixed list — nytimes.com, stripe.com and zara.com each cost $0.005 to rule out in the measured run. If you only want Shopify rows kept, set emitNonShopify: false and non-Shopify domains are skipped unbilled.
  3. Headless stores return the verdict but few fields. ~19% of the measured Shopify stores (7 of 36) run custom frontends: products-json-only stores (fashionnova) still give you catalog counts and prices but no theme; cdn-assets-only stores (ruggable) give you little beyond the verdict. shopifyDetection tells you exactly how sure the row is — filter on it.
  4. themeIsCustom: true does not mean "not Dawn." It means the theme was not installed from the official theme store. Big stores fork a base theme: deathwishcoffee reads themeName: "Dawn" + themeIsCustom: true (a customized Dawn). Only 3 of 26 themed stores in the sample ran an unmodified official-store theme (Split, Pipeline, Symmetry — each with its themeStoreId).
  5. currency / countryCode are as served to a US datacenter exit IP. Localized storefronts answer per-visitor (the same store served CAD to a Canadian IP and USD through the Apify proxy in testing). priceMin/priceMax come from /products.json, which serves the store's base currency regardless of visitor location.

What you get

One row per unique input domain. scrapedAt is a full UTC timestamp; publish dates are the store's own ISO timestamps.

GroupFieldsExample
VerdictisShopify, shopifyDetection, status, passwordProtectedtrue · storefront
Identitydomain, finalUrl, myshopifyDomain, shopId, storeName, storeDescriptiondeathwishcoffee.myshopify.com · 2717209
ThemethemeName, themeVersion, themeStoreId, themeIsCustom, themeLabelDawn · 10.0.0 · custom
CatalogproductCount (+IsExact), collectionCount (+IsExact), vendorCount, topVendors[], topProductTypes[]146 exact · 124 collections
PricingpriceMin, priceMax, currency5119.99 USD
ActivitynewestProductPublishedAt, oldestProductPublishedAt2026-08-14…
LocalecountryCode, localeUS · en
Tech stackappsDetected[], pixelsDetected[], paymentsDetected[], appCountKlaviyo, Rebuy, Gorgias…
ContactcontactEmail, contactEmails[], socialLinks{}, organizationAddresshelp@allbirds.com
Provenanceerror (no-verdict rows only), scrapedAt

shopifyDetection tiers, strongest first: storefront (Shopify globals on the page) → products-json-only (headless frontend, open catalog API) → headers-only (Shopify response headers) → cdn-assets-only (only cdn.shopify.com asset references — treat as "almost certainly Shopify, headless") → none (not Shopify).


Field fill — measured on 36 Shopify stores

A 45-domain mixed list (big DTC brands, mid-size stores, 3 non-Shopify controls, 1 dead domain), 2026-08-15, through the Apify datacenter proxy. Percentages are against the 36 Shopify-verdict rows, sorted descending so the sparse fields are impossible to miss.

FieldFillNotes
storeName / storeDescription97.2%og:site_name / meta description
socialLinks94.4%share-links excluded; first profile link per network
productCount91.7%28 of 33 exact at the default depth; the rest flagged productCountIsExact: false
collectionCount91.7%exact up to 1,000
priceMin / priceMax91.7%store base currency, from real variant prices
vendorCount / topVendors / topProductTypes91.7%
newestProductPublishedAt / oldest…91.7%catalog activity signal
appsDetected (≥1)91.7%average 4.5 apps per store, max 10
paymentsDetected (≥1)91.7%Shop Pay, Afterpay, Klarna, Sezzle, Affirm, PayPal, Apple Pay
myshopifyDomain / shopId77.8%absent on headless frontends
currency / countryCode / locale77.8%absent on headless frontends
pixelsDetected (≥1)75.0%Meta, TikTok, Pinterest, Snap, GTM/GA4, Microsoft, Criteo…
themeName / themeVersion72.2%headless stores have no Liquid theme
contactEmail38.9%homepage-published only — no guessing. Read gotcha 1.
organizationAddress16.7%JSON-LD only; most stores publish none
themeStoreIdlow on big brands — 0 of 8 on the shipped defaultNot a gap: it is null at the source whenever a store runs a forked or bespoke theme, which every large DTC brand does. Re-probed live 2026-08-19: allbirds, deathwishcoffee, stevemadden, kyliecosmetics, colourpop, brooklinen, thesill, pinklily, trueclassictees, ohpolly all publish "theme_store_id":null; beardbrand.com (stock Split theme) publishes 842 and the Actor returns it. themeStoreId: null alongside a non-null themeName is exactly what themeIsCustom: true means.

Every run prints its own measured fill in the log. The shipped 8-domain default printed: productCount 87.5%, apps 87.5%, socials 87.5%, theme 75.0%, email 25.0%.


How to run it

1. Qualify a list (the usual job)

{ "domains": ["brand-a.com", "brand-b.com", "brand-c.com"] }

Paste up to 10,000 domains, with or without https:// — duplicate spellings (www.brand-a.com, https://brand-a.com/about) are normalized and dropped before billing (measured: a 6-entry input with 3 duplicate spellings billed exactly 2 rows).

2. Shopify-only output

{ "domains": ["…"], "emitNonShopify": false }

Non-Shopify domains are skipped and never billed. Use when your list is scraped from ads or marketplaces and you only want the Shopify stores kept.

3. Fast verdicts, no catalog walk

{ "domains": ["…"], "maxProductPages": 1, "fetchCollections": false }

2 requests per store instead of 3–5. You keep the verdict, theme, apps, socials and email; productCount stays exact only for stores under 250 products. Same price per store — depth costs you time, not money.

4. Deep catalog counts

{ "domains": ["…"], "maxProductPages": 40 }

Counts up to 10,000 products exactly. productCountIsExact: false on a row means the cap stopped the walk and the true catalog is larger than the number shown.

Scheduling and integrations

Save the input as a Task and attach an Apify Schedule for a weekly re-scan of your target accounts (theme changes, app installs/uninstalls and catalog growth are all re-measured each run). The dataset exports to CSV/JSON/Excel/Sheets and the standard Apify integrations (Zapier, Make, n8n, webhooks, MCP). From the API:

curl -X POST "https://api.apify.com/v2/acts/scrapersdelight~shopify-store-analyzer/runs?token=YOUR_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"domains":["allbirds.com","gymshark.com"]}'

Sample row

A real row from an actual run on the shipped defaults, 2026-08-15:

{
"domain": "deathwishcoffee.com",
"finalUrl": "https://www.deathwishcoffee.com/",
"status": "analyzed",
"isShopify": true,
"shopifyDetection": "storefront",
"passwordProtected": false,
"myshopifyDomain": "deathwishcoffee.myshopify.com",
"shopId": 2717209,
"storeName": "Death Wish Coffee",
"storeDescription": "Bold, Smooth and Delicious since 2012. We source USDA Organic and Fair Trade Certified arabica and robusta coffee beans…",
"themeName": "Dawn",
"themeVersion": "10.0.0",
"themeStoreId": null,
"themeIsCustom": true,
"themeLabel": "Copy of deathwish-shopify-20/production",
"productCount": 146,
"productCountIsExact": true,
"collectionCount": 124,
"collectionCountIsExact": true,
"priceMin": 5,
"priceMax": 119.99,
"currency": "USD",
"countryCode": "US",
"locale": "en",
"vendorCount": 15,
"topVendors": ["Death Wish Coffee Company", "Death Wish Coffee", "Sportiqe", "Planet Apparel", "Deneen Pottery"],
"topProductTypes": ["Apparel", "Coffee", "Accessories", "Coffee Bundle", "On-The-Go Drinkware"],
"newestProductPublishedAt": "2026-08-14T08:40:37-04:00",
"oldestProductPublishedAt": "2014-03-12T13:35:00-04:00",
"appsDetected": ["Klaviyo", "Rebuy", "Gorgias", "Postscript", "Smile.io"],
"pixelsDetected": ["Google Tag Manager"],
"paymentsDetected": ["Shop Pay", "Afterpay", "Apple Pay"],
"appCount": 5,
"socialLinks": {
"twitter": "https://twitter.com/deathwishcoffee",
"facebook": "https://www.facebook.com/deathwishcoffee",
"instagram": "https://www.instagram.com/deathwishcoffee/",
"youtube": "https://www.youtube.com/channel/UC1uurJMded2rRJioe8yka7g"
},
"contactEmail": null,
"contactEmails": [],
"organizationAddress": null,
"error": null,
"scrapedAt": "2026-08-15T04:10:06.861Z"
}

Fields people misread:

  • themeLabel is the store's own internal theme name (
    "Copy of deathwish-shopify-20/production"
    ) — often more revealing than themeName itself.
  • priceMin: 5 is a real $5 variant (stickers, samples). Judge the price band with both ends, not just the floor.
  • contactEmail: null on a store with 5 detected apps is normal — this brand publishes no email on its homepage. That is the 38.9% fill from the table above, not a bug.

Input

FieldTypeDefaultWhat it does
domainsstring list8 live storesThe stores to analyze. With or without https://; duplicates dropped before billing; up to 10,000 per run. Send no domains at all (a bare {} from the API or an agent) and the Actor does not fail — it runs a 3-store demo sample (allbirds.com, deathwishcoffee.com, colourpop.com) so you get real rows to inspect. Those 3 rows are billed like any other verdict: $0.015.
maxProductPagesinteger8Catalog pages of 250 to walk. 8 = exact counts up to 2,000 products. 0 skips the catalog.
fetchCollectionsbooleantrueCount collections (exact up to 1,000).
emitNonShopifybooleantrueOff = non-Shopify domains skipped, never billed.
maxConcurrencyinteger5Parallel domains. Requests within one store are always sequential — no store ever sees concurrent traffic from this Actor.
proxyConfigurationproxyApify datacenterMeasured: Shopify serves identical bytes on every rung, so the cheap rung is the default. Blocked statuses retry once through RESIDENTIAL automatically.

Pricing

$0.005 per store analyzed — $5 per 1,000. Charged on the store-analyzed event. No monthly platform fee from this Actor.

RunStoresCost
The shipped default8$0.04
An agency pitch list200$1.00
A lead-scoring batch1,000$5.00
A full TAM sweep10,000$50.00
  • You are charged per verdict, not per attempt. Blocked and unreachable domains are pushed as rows (so you can see what happened, with the HTTP status in error) without the charge event — in the measured 45-domain run, 6 of 45 domains were not billed.
  • Duplicate spellings are dropped before billing.
  • Rows are charged as they are pushed (Actor.pushData(items, 'store-analyzed')), so a budget cap gets you whole rows and stops, never a half-billed dataset.
  • Depth settings (maxProductPages, fetchCollections) change run time, not price.
  • A run that hits its time limit stops cleanly instead of being killed. The Actor keeps a wall-clock budget from the platform's own run timeout, stops taking new domains before it, delivers everything already collected, and ends Succeeded with a status message naming how many domains were never started. Those un-started domains are not billed — re-run them with a longer run timeout or in smaller batches. Measured 2026-08-19: 301 domains at maxProductPages: 40 against a 120 s wall → finished in 74 s, 3/3 runs, 57 verdict rows delivered and billed, 0 rows lost, never TIMED-OUT.

How it works, and what was measured

Per domain, 3–5 requests at the defaults: the homepage (Shopify globals, JSON-LD, app/pixel signatures, socials, mailto links), then /products.json?limit=250 paged until a short page (an exact count) or the cap, then /collections.json. The catalog probe runs even when the homepage carries no Shopify markers — that is how headless-frontend stores with an open catalog API (fashionnova) are caught instead of misfiled as "not Shopify."

Transport ladder, measured 2026-08-15 with got-scraping:

RungResult
Direct (reported and then ignored — home-IP recon lies)200, identical bytes
Apify proxy, datacenter200, identical bytes
Apify RESIDENTIAL200, identical bytes
Apify RESIDENTIAL + pinned session200, identical bytes

Shopify's edge does not discriminate between rungs, so the cheap datacenter rung is the default and you are not billed residential bandwidth you do not need. Sustained load through the Apify datacenter proxy: 20 calls (10 domains × homepage + catalog) at concurrency 4 = 18/20 = 90.0% in 26.5 s — and both misses were bombas.com, which serves HTTP 429 on every rung including residential and a home IP (a store-side bot wall). Excluding that one walled store: 18/18 = 100%. Store-side walls exist on roughly 1 in 10 big-brand domains (4 of 45 measured: bombas, meundies, huckberry, mizzenandmain) — those rows come back unbilled with the status in error.

Duplicates, measured in both directions: contiguous /products.json pages returned 0 duplicate product ids across two full catalog walks (291 and 146 products), so counts never double-count; and the run itself asserts one row per unique domain before it is allowed to succeed.

robots.txt: Shopify's generated robots.txt opens with "Public product, collection, page, blog, policy, cart, and localized HTML is crawlable" (fetched live 2026-08-15). Its Disallow list (/admin, /cart/, /checkout, /orders, /account, /cart.js, sort/ filter parameter URLs…) never mentions /products.json or /collections.json — and this Actor touches none of the disallowed paths. It reads currency from the homepage globals specifically because /cart.js is disallowed. Per-store traffic is sequential — one request at a time per domain, concurrency only across different domains.


Honest limits

  • No revenue or traffic estimates. Rival analyzers headline "revenue estimates" — numbers no public endpoint provides, so they are models, not measurements. Everything in this row is read from the store itself; nothing is modeled. If a field cannot be read, it is null, not guessed.
  • contactEmail fill is 38.9% and comes from the homepage only. This is not an email finder.
  • App detection is homepage-signature-based. Apps that load only on product/checkout pages (some upsell and shipping apps), server-side apps, and apps with no front-end footprint are invisible. appsDetected is a floor, not a census — 70 signatures curated for the highest-signal revenue apps (reviews, subscriptions, SMS/email, support, BNPL).
  • Headless stores yield thin rows (see gotcha 3) — the verdict and detection tier are the deliverable there.
  • ~1 in 10 big-brand domains runs its own bot wall and comes back blocked, unbilled. This Actor does not fight DataDome/Kasada-class walls for a $0.005 row.
  • Password-protected (pre-launch) stores return passwordProtected: true with the verdict — useful as a "store about to launch" signal, but catalog fields are null.
  • One row per domain, ever. Multi-region stores on separate domains (gymshark.com vs gymshark.eu? paste both) are separate rows; this Actor never expands your list.

Who buys this

  • Agencies pitching Shopify services — qualify a pitch list: platform, theme (stock vs custom), catalog size, price band and app gaps, in one CSV.
  • Shopify app vendors — score leads by tech stack: who runs a competitor's app, who runs no reviews/subscription/SMS app at all (appsDetected as a gap map).
  • BNPL / payments / logistics vendorspaymentsDetected shows exactly which of Shop Pay / Afterpay / Klarna / Sezzle / Affirm a store already offers.
  • Competitive & market researchers — catalog size, price range, publish-date activity and ad-pixel mix across a whole vertical.
  • Theme and CRO agenciesthemeName/themeVersion/themeIsCustom find stores on aging stock themes.

FAQ

Does this find Shopify stores for me? No — you supply the domains; it analyzes them. Store discovery is a different job (our Shopify App Store Leads Scraper covers the app-publisher side).

Do I need a login, API key or residential proxies? No. Everything is public storefront data, and the measured ladder shows the cheap datacenter rung works everywhere Shopify itself answers.

Will every row have an email? No — 38.9% measured. It is whatever the homepage publishes. Read gotcha 1 before buying.

Is the product count exact? productCountIsExact tells you per row. At the default depth, 28 of 33 counted stores were exact; raise maxProductPages to 40 for exact counts up to 10,000.

What happens on a non-Shopify domain? A billed isShopify: false verdict row (that answer is usually the point), or set emitNonShopify: false to skip them unbilled.

What happens on a blocked or dead domain? An unbilled row with status: "blocked" or "unreachable" and the HTTP status in error. You never pay for a non-answer.

Will a run ever succeed with zero rows? No. A run that produces zero billable verdicts throws, and the error message breaks down exactly what happened (blocked / unreachable / filtered) so you can tell a list problem from a site problem.


This Actor reads public storefront pages and the public catalog endpoints each store serves to every visitor. It does not log in, does not touch checkout, cart, admin or any robots.txt-disallowed path, and collects nothing behind authentication. Store rows can contain business contact data. You are responsible for complying with each store's terms, Shopify's terms, and with how you use the data. Shopify® is a trademark of Shopify Inc.; this Actor is not affiliated with, endorsed by, or connected to Shopify Inc. or any store analyzed.


Feedback

Found a store that misdetects, or want a signature added to the app list? Open an issue on the Issues tab — signature additions ship fast. If the Actor earns it, a review on the Reviews tab helps other buyers find it.