How-to
How to run Shopify Store Audit & Tech-Stack Lead Scorer
Step-by-step: the exact input, what each field does, and the real rows that come back from public storefront.
You have a list of Shopify domains and a question about each one: what is this store actually running? Which reviews app, which email tool, which theme, how big is the catalog, are they discounting. If you sell a Shopify app, that question decides who is worth an email. If you run an agency, it decides what you pitch. The manual answer is to open each store, hit View Source, and read the script tags — which works, and is genuinely fine for three stores. It stops being fine at thirty, and it produces nothing you can sort, filter, or hand to a CRM.
This actor does that read for you across a whole list and returns it as rows.
What you’ll need
Nothing but an Apify account. The actor talks to public storefront directly.
No API key, no merchant permission, no app install, no CAPTCHA-solving credentials. Everything it
reads is what a visitor with the browser devtools open can already see: the storefront HTML and the
store’s own /products.json. That’s why it’s cheap and why it rarely breaks. The proxy toggle
exists but is off by default — turn it on only if a specific store blocks the run.
Step 1 — Open the actor
Open Shopify Store Audit & Tech-Stack Lead Scorer on the Apify Store and press Try for free. The actor’s own page on this site lists its live health and pricing.
Step 2 — Fill in the input
| Field | Type | Required | What it does |
|---|---|---|---|
domains | array | yes | Shopify store domains or URLs to audit, e.g. ‘allbirds.com’. Paste a list to bulk-audit a prospect list. We audit the domains you provide (we don’t discover stores). |
targetGaps | array | no | App categories that should be MISSING for a store to count as a lead — sets ‘matches_criteria’. E.g. a reviews-app vendor sets [‘reviews’]. Categories: reviews, email, search,… |
includeProducts | boolean | no | When off (default), return store signals only (fast, cheap — the lead-gen need). Turn on to also include the (slimmed) product catalog. |
compareToPrevious | boolean | no | When on (default), diff each store against the previous run and report what changed — apps added/removed and product-count delta. Run on a schedule to track stores over time. (default True) |
maxProductsPerStore | integer | no | Cap on products sampled per store (bounds cost). Product count caps here for very large stores. (default 1000) |
Two fields decide what you actually get. domains is the one people misread: this actor audits
the domains you give it. It does not go looking for Shopify stores, and there is no “find me all
stores in cosmetics” mode — you bring the list, it enriches the list. Bare hosts or full URLs both
work; https://Allbirds.com/collections/mens and allbirds.com normalise to the same thing.
targetGaps is what turns an audit into a lead score. Give it the app categories that must be
absent for a store to count as a prospect, and matches_criteria comes back true only when
every one of them is missing. A reviews-app vendor sets ["reviews"]. Leave targetGaps empty and
matches_criteria is null — you still get all the detection, just no verdict. The seven
categories are reviews, email, search, upsell, loyalty, subscription and chat.
A working input:
{
"domains": [
"allbirds.com",
"colourpop.com"
],
"targetGaps": [
"reviews"
],
"compareToPrevious": true
}
Step 3 — Run it
Press Start. Rows are pushed to the dataset as they’re found, so the run log fills in as it works.
You get exactly one row per domain you submitted — no more, no fewer. Non-Shopify domains and
domains that don’t respond still come back as rows, with is_shopify: false, so you can see what
was dropped rather than silently losing it. An empty detected_apps list is not a failure: it
usually means the store genuinely runs none of the apps in the signature list, or loads them
server-side where the storefront markup doesn’t give them away. Check is_shopify first — if
that’s true and the app list is empty, the detection ran and found nothing.
Step 4 — Read the output
Each run returns a labelled table, not raw JSON:
Every row looks like this — a real row from a real run:
{
"domain": "allbirds.com",
"is_shopify": true,
"detection_signals": [
"cdn.shopify.com",
"Shopify.theme"
],
"shopify_plus": false,
"theme_name": "Dawn",
"detected_apps": [
{
"name": "Yotpo",
"category": "reviews"
},
{
"name": "Klaviyo",
"category": "email"
}
],
"app_categories": [
"email",
"reviews"
],
"has_reviews_app": true,
"has_email_app": true,
"has_search_app": false,
"missing_categories": [
"search",
"upsell",
"loyalty",
"subscription",
"chat"
],
"matches_criteria": false,
"product_count": 629,
"price_min": 18.0,
"price_max": 160.0,
"currency": "USD",
"discount_rate": 0.12,
"new_products_30d": 7,
"products_json_accessible": true,
"first_seen": false,
"apps_added": [
"Klaviyo"
],
"apps_removed": [],
"product_count_delta": 12,
"source_url": "https://allbirds.com"
}
| Field | Example value | Meaning |
|---|---|---|
domain | allbirds.com | Store domain audited |
is_shopify | True | Whether the domain is a confirmed Shopify store |
detected_apps | [{"name": "Yotpo", "category": "reviews"}, {"name": "Klaviyo", "category": "email"}] | Installed apps detected from the storefront ({name, category}) |
app_categories | ["email", "reviews"] | Categories of detected apps |
missing_categories | ["search", "upsell", "loyalty", "subscription", "chat"] | App categories with NO detected app — the prospecting gaps |
matches_criteria | False | True when all your target-gap categories are missing (a lead) |
has_reviews_app / has_search_app / … | — | Per-category presence flags (reviews, email, search, upsell, loyalty, subscription, chat) |
theme_name | Dawn | Storefront theme name |
Most people came for missing_categories and matches_criteria — that’s the prospecting verdict.
A few things to watch. matches_criteria is null, not false, when you didn’t set targetGaps.
product_count is capped by maxProductsPerStore, so a store with more products than the cap
reports the cap and sets product_count_is_floor: true — treat that number as a floor, not a total.
And when a store has disabled /products.json (products_json_accessible: false), the count falls
back to a sitemap tally and the catalog signals that depend on product data — price_min,
price_max, discount_rate, new_products_30d — come back null. That’s expected, not a bug.
Step 5 — Export it
Open the Dataset tab and export to CSV, JSON, or Excel — or pull the same rows from the API, which is what you want if this is going to run on a schedule.
What it costs
Pay-per-store: $0.01 per Shopify store audited, so a 1,000-store prospect list is about $10.00. Domains that turn out not to be Shopify, or that never respond, are pushed to the dataset for free — you don’t pay to find out a domain was a dead end. Apify’s own platform compute is billed separately on your plan; this actor uses plain HTTP requests rather than a browser, which keeps that side small.
Where the data comes from
This reads public storefront directly. The target is Public storefront JSON. Every night a canary runs this actor against that live source and diffs the result against a frozen fixture — what “verified” means.
There is no privileged access here and no integration. Every Shopify store serves a /products.json
endpoint with its catalog in it, and serves storefront HTML with its theme name and its apps’ script
tags embedded — that is the whole source. The annoyance isn’t getting the data, it’s that it arrives
as an undifferentiated wall of JSON and markup: apps are identified by CDN hostnames buried in
script tags, the product count is only the length of a paginated list, and roughly one store in
seven turns /products.json off entirely and needs a sitemap fallback. Doing that across a list by
hand is the part nobody wants to do twice.
See it used
Detect a Shopify Store’s Apps & Theme is the single-store version — one domain, what it runs. Find Shopify Stores Missing a Reviews App is the app-vendor version — a list in, the ones with a gap flagged on the way out. And Audit a Competitor’s Shopify Tech Stack uses the same row to read a rival’s stack and catalog posture.
If what you actually want is to watch a store change rather than describe it once, reach for the Shopify Price & Stock Change Tracker instead: this actor tells you what a store is, the tracker tells you what moved — price changes, stock flips, products added and pulled. The natural pairing is to audit once and then watch.
Last updated 2026-07-13