Shopify Store Leads — Catalog Size, Apps, Contacts avatar

Shopify Store Leads — Catalog Size, Apps, Contacts

Pricing

from $4.50 / 1,000 qualified stores

Go to Apify Store
Shopify Store Leads — Catalog Size, Apps, Contacts

Shopify Store Leads — Catalog Size, Apps, Contacts

Find and qualify Shopify stores, or enrich domains you own. Each lead returns catalog size, price band, theme, installed apps, published policies, new products a month, emails, phones and socials. Filter by country, category, keyword, size, ships-to, price or apps. You pay only for rows you keep.

Pricing

from $4.50 / 1,000 qualified stores

Rating

0.0

(0)

Developer

Richard Feng

Richard Feng

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 hours ago

Last modified

Share

Shopify store leads, qualified: store size, installed apps, publishing activity and ratings, with business emails, phones and addresses. Pay only for stores that match.

Shopify store leads you can qualify before you reach out. Every row is one store: its business emails, phone numbers, social profiles and address — and how big it is, what it runs, and whether it is still selling. Find stores by what they sell, where they are and what they have installed, or paste the domains you already have. You pay only for stores that match your filters.

Why choose this Actor?

Know a store before you pitch it. Most Shopify lead lists tell you a store exists and hand you an email address. This one also returns the product count, the price band, the product types and vendors, the theme and the installed apps, how many new products the store publishes a month and how many days since its last. A 6,500-product catalog and a 13-product boutique look the same in a list of emails; here they don't.

Contacts in the same row. Business emails, phone numbers and social profiles from the store's page on the Shop app, its storefront and its own contact page — plus its business address and its Shop app rating. Every address the store publishes — info@, hey@, kundenservice@ alike — except the ones nobody reads, like no-reply@.

Filter on what your pitch depends on. Country, product category, keyword, catalog size, average price, the countries a store ships to, stock, recent publishing, the apps a store runs — or has not installed yet — the social networks it links, and whether it publishes an email or a phone number. A keyword or a category is searched on the Shop app, Shopify's marketplace, so you find stores by what they actually sell.

Pay only for stores that match. A store your filters reject is never returned and never charged, and a store reached twice in one run is charged once. $5.00 per 1,000 stores on the Free plan, down to $4.50 on Business.

Try it on your own stores →

🚀 Quick start

  1. Click Try for free. The input opens prefilled with a few well-known stores: start it as it is, and within a minute you have rows to look at.
  2. To profile stores you already know, paste their domains into Store URLs — one per line; gorjana.com and https://gorjana.com both work.
  3. To find new stores instead, leave Store URLs empty and set a Keyword or a Product category, then any filters — Countries, Minimum products, Published a product within (days), the apps a store should or should not run.
  4. Set Maximum stores. It caps how many rows the run returns, and so the most it can charge you.
  5. Click Start, then download the results from the Storage tab as JSON, CSV, Excel or XML — or pull them from the API.

Start small, check the rows look how you expect, then raise Maximum stores.

💡 What people use it for

Sell to stores that run an app you integrate with. Stores running Klaviyo or Okendo that link an Instagram account, in the US and the UK:

{ "hasApps": ["klaviyo", "okendo"], "hasSocials": ["instagram"], "countries": ["US", "GB"], "maxItems": 200 }

Find stores that don't show a competitor's app yet. Stores on Klaviyo with no reviews app on their storefront:

{ "hasApps": ["klaviyo"], "excludeApps": ["judge-me", "loox", "okendo", "stamped", "yotpo"], "countries": ["US"], "maxItems": 200 }

Build a list of active stores in a niche. US jewellery stores with a real catalog that published a product in the last 90 days:

{ "countries": ["US"], "category": "jewelry", "minProducts": 50, "activeWithinDays": 90, "maxItems": 500 }

Find stores by what they sell, each with its Shop app rating and business address:

{ "query": "coffee", "countries": ["US"], "maxItems": 100 }

Qualify mid-market stores that ship to you, are trading, and can be contacted:

{ "shipsToCountries": ["US"], "minAvgPrice": 5000, "maxAvgPrice": 30000, "inStockOnly": true, "requireEmail": true, "maxItems": 200 }

Profile stores you already know:

{ "storeUrls": ["gorjana.com", "allbirds.com"], "maxItems": 10 }

📋 Input

Everything is optional. With a query or a category, the stores come from the Shop app's search for it, and from nowhere else. With neither, the Actor discovers stores from its built-in list of 6,542 verified stores, then from Common Crawl. Either way it looks each store it keeps up on the Shop app.

FieldTypeDefaultWhat it does
storeUrlsarray—Domains to profile. Set this and discovery is skipped entirely.
querystring—Find stores selling this: searched on the Shop app, which is then the only source of stores. With useShopApp off, or on your own storeUrls, it is matched against store name, description and domain instead.
categorystring—Product category. With no query, searched on the Shop app, which is then the only source of stores; otherwise matched against the store's own product types.
countriesarray—Two-letter country codes, e.g. ["US","GB"].
minProductsinteger—Skip stores with fewer products than this.
maxProductsinteger—Skip stores with more products than this.
activeWithinDaysinteger—Only stores that published a product this recently.
excludeKeywordsarray—Drop stores matching any of these words.
shipsToCountriesarray—Only stores shipping to at least one of these countries.
minAvgPriceinteger—Minimum average product price, in minor units — 5000 is 50.00.
maxAvgPriceinteger—Maximum average product price, in minor units.
inStockOnlybooleanfalseOnly stores with something actually in stock.
hasAppsarray—Only stores running these apps, by handle — klaviyo, judge-me, okendo.
appMatchModestringanyWhether hasApps means any of them or all of them.
excludeAppsarray—Drop stores running any of these apps — find stores that have not installed a competitor yet.
hasSocialsarray—Only stores linking at least one of these networks — instagram, tiktok, facebook.
requireEmailbooleanfalseOnly stores that publish a business email address.
requirePhonebooleanfalseOnly stores that publish a phone number.
maxItemsinteger100Maximum stores to return. The hard cap on what the run can charge. To cap spend in currency instead, set Maximum total charge in the run options — the platform enforces it.
includeCatalogbooleantrueProduct/collection counts, price band, types, vendors.
includeContactsbooleantrueBusiness emails, phones and social profiles, and the business address. The ones on the store's Shop app page come first; the storefront fills in the rest.
includeTechStackbooleantrueTheme, installed apps, accepted card brands.
useShopAppbooleantrueUse the Shop app. With a query, or a category when there is no query, its product search is where the stores come from. Every store that passes your filters is then found on the Shop app — by that search, or by its own name — for its rating and, with includeContacts, its business address and the contacts it lists there. Set false to read only the stores' own storefronts, found through the seed and Common Crawl.
useSeedbooleantrueExamine the built-in list of verified stores before Common Crawl, when there is no query or category for the Shop app to search.
ccIndexstring—Pin a specific Common Crawl index. Leave empty for the newest.
proxyobjectApify ProxyLeave this on — see the FAQ.

📤 Output

One row per store, 40 fields in seven groups:

GroupFields
Identity and locationurl, domain, myshopifyDomain, name, description, country, province, city, currency, languages, shipsToCountries
CatalogproductCount, collectionCount, priceMin, priceMax, priceAvg, pricedFrom, productTypes, vendors, sizeBand
ActivitynewestProductUTC, oldestProductUTC, daysSinceLastProduct, isActive, productsPerMonth
Tech stacktheme, apps, policies, announcementBarText, cardBrands, offersShopPayInstallments
Contactsemails, phones, socials
From the Shop apprating — average, ratingCount, reviewCount — and address
ProvenancediscoveredVia, scrapedUTC

Real output, trimmed for length:

{
"url": "https://www.gorjana.com/",
"domain": "www.gorjana.com",
"myshopifyDomain": "gorjana.myshopify.com",
"name": "gorjana",
"description": "Complete your look with jewelry designed to layer...",
"country": "US",
"province": "California",
"city": "Laguna Beach",
"address": ["3275 Laguna Canyon Rd Ste R1", "Laguna Beach, California 92651", "United States"],
"currency": "USD",
"languages": ["en"],
"shipsToCountries": ["AC", "AD", "AE", "..."],
"catalog": {
"productCount": 983,
"collectionCount": 575,
"priceMin": 3000,
"priceMax": 599000,
"priceAvg": 17884,
"pricedFrom": 250,
"productTypes": ["Anklets", "Bracelets", "Charms", "Earrings", "Gift Cards", "Hand Chains", "Necklaces", "Rings"],
"vendors": ["Bespoke", "Fine", "Layering Set", "..."],
"sizeBand": "medium"
},
"activity": {
"newestProductUTC": 1790111736,
"oldestProductUTC": 1767325861,
"daysSinceLastProduct": 1,
"isActive": true,
"productsPerMonth": 28.9
},
"theme": { "name": "[RELEASE] 5.2.0", "id": 166571606147, "version": "" },
"apps": [{ "handle": "klaviyo", "name": "Klaviyo" }, { "handle": "okendo", "name": "Okendo" }],
"policies": [],
"announcementBarText": null,
"cardBrands": ["visa", "master", "american_express", "discover"],
"offersShopPayInstallments": true,
"contacts": {
"emails": ["customercare@gorjana.com"],
"phones": ["8668290030"],
"socials": {
"x": "https://twitter.com/gorjana_brand",
"facebook": "https://www.facebook.com/gorjanabrand",
"instagram": "https://www.instagram.com/gorjana",
"youtube": "https://www.youtube.com/@gorjanabrand",
"tiktok": "https://www.tiktok.com/@gorjana",
"pinterest": "https://www.pinterest.com/gorjanabrand"
}
},
"rating": { "average": 4.81, "ratingCount": 18510, "reviewCount": 4610 },
"discoveredVia": "input",
"scrapedUTC": 1790214009
}

Two conventions worth knowing: prices are integers in minor units, so 17884 means $178.84, and timestamps are epoch seconds.

productsPerMonth is what separates a store publishing 30 products a month from one that published its last 30 over four years — isActive calls both of them active.

policies is empty for this store because gorjana links its policies as ordinary pages rather than at Shopify's canonical /policies/… URLs, which is worth knowing before you filter on it. Across a sample of ordinary stores about eight in ten use the canonical form and return a list like ["refund-policy", "shipping-policy", "terms-of-service"] — but large direct-to-consumer brands mostly do not: of nine well-known ones checked, one published canonical policy URLs. Read an empty list as "not published at the canonical URL", never as "this store has no refund policy".

announcementBarText is the storefront's announcement bar, verbatim and in whatever language the merchant wrote it in — "FREE SHIPPING FOR ORDERS OVER £70", "DESCUENTO DEL 10% PARA COMPRAS SUPERIORES A 80€",

"Final Sale. No Returns or Exchanges."
It tells you what the store is promoting right now, which is the difference between a shop that is trading and one that is merely online. Null for gorjana, and for about four stores in ten.

rating is the store's rating on the Shop app, built by Shop from its own reviews and approved review apps, so no storefront carries it. address is the business address a store gives the Shop app, one entry per line as the Shop app formats it: street, then town, region and postcode, then country. It is not split into parts, because the layout is the country's. The Actor finds every store it keeps on the Shop app: a store the Shop app's search found arrives with its rating, and any other — like gorjana here, named in storeUrls — is looked up there by its own name and matched on its Shopify id. gorjana's Shop app page also gave the phone number and the Pinterest profile above: its homepage prints the number without linking it and does not link Pinterest at all, so the storefront alone gave neither. Of 30 coffee stores found through the Shop app's search on 2026-09-23, all 30 carried a rating, 25 an address, 24 an email and 23 a phone.

💰 Pricing

Pay per store returned, with no monthly fee. The price per store falls with your Apify plan:

Apify planPer 1,000 storesPer store
Free$5.00$0.0050
Starter$4.80$0.0048
Scale$4.60$0.0046
Business and above$4.50$0.0045
  • A store your filters reject is never charged — it is never returned. You pay for the rows you keep.
  • A store reached twice in one run is charged once.
  • Two ways to cap a run: Maximum stores caps the rows and so the charge, and Maximum total charge in the run options caps it in dollars — the platform enforces it.
  • Each run also carries a start fee of $0.00005.

⚠️ What this Actor does not do

Stated up front so you can judge fit before paying.

  • The price band is a sample, not a census. Computed from up to 250 products; catalog.pricedFrom tells you how many were used. Product and collection counts are exact — the store reports those itself.
  • App detection sees the public storefront only. A purely back-office app with no asset on the page is invisible. A detected app is real; an undetected one is not proof of absence.
  • Contacts are what the store publishes, as it publishes them. Every email address on its storefront, its Shop app page or its contact page is kept — a named person's too, when the store lists one — except no-reply@ addresses and the placeholders themes and apps ship with. No job titles or LinkedIn profiles: nothing the store did not publish itself.
  • A keyword run finds what the Shop app's search finds, and nothing more. With a query or category, the stores come from that search alone, custom domains included; a store the Shop app does not list, or does not show for that word, is not found — you can still profile it directly via storeUrls. Without either, discovery walks the built-in list and Common Crawl, which finds stores through their .myshopify.com address: roughly half have a custom domain configured, and a store only ever crawled at its custom domain may not be discoverable.
  • rating and address come from the Shop app. A store its search found carries them; any other is looked up by its own name and matched on its Shopify id. A store the Shop app does not list under that name has rating: null and address: [] — as, sometimes, does one whose products do not ship to where the request comes from, which the Shop app's search leaves out. So does every store with useShopApp off.
  • Shop app requests are made one at a time, each from its own IP. A stored store costs one when the Shop app's search found it, two otherwise — a lookup, then its page when includeContacts is on — and the Actor spaces them half a second apart. Stores rejected by your filters never cost one. A refused request is sent again from another IP. If the Shop app still stops answering a store's requests, the run carries on and the rest of its stores come back without the Shop app's data; if it stops answering the search itself, a keyword run ends with the stores it has and says why.
  • policies counts Shopify's canonical policy pages only. A store that hand-builds a /pages/refund-policy instead is reported as having none. Empty means "not published at the canonical URL", not "this store has no refund policy".
  • announcementBarText is the bar's text, not a parsed promotion. There is no free-shipping threshold, discount percentage or promo-code field, and that is measured, not an omission: the copy is written in the store's own language, so an English pattern would report every non-English store as running no promotion — and a percent-off pattern run over a storefront matches product prices, not promotions. You get the sentence; read it yourself. How much of a rotating bar you get depends on the theme. Where each slide sits in its own element you get one message; where the theme puts them all in one element you get them all, joined — tentree.com returns
    "FREE SHIPPING ON ORDERS OVER $100 FREE SHIPPING ENDS MONDAY. CODE: FREESHIP DEEPEST DISCOUNTS: 30-50% OFF SHOP NOW EVERY ITEM PLANTS 10 TREES"
    , which is four promotions at once. Where a theme splits one message across nested elements you get the innermost piece. Null means the store has no bar, or fills it in after the page renders.
  • productsPerMonth is measured over the sampled window. For a store with more products than the sample it is the recent rate; for a smaller store it is the lifetime average. It is null when the sample is too thin to support a rate.
  • The price filters compare each store in its own currency. minAvgPrice is matched against the store's own prices, so a run spanning several currencies is comparing numbers, not value. Pair them with countries when that matters.
  • Stores that don't answer are skipped, not guessed at — and cost you nothing.

🧰 Works well with

ActorUse it for
Shopify ScraperProducts and collections from a store this Actor found. The natural next step: qualify the store here, then pull its catalog there.
Schema Markup Scraper & SEO AuditorAudit the structured data and SEO of any store in your list.
Anytime Mailbox ScraperBusiness locations and CMRA records — another lead source to enrich the same list.
Indeed Jobs ScraperHiring signals on the companies you qualify.
WooCommerce ScraperCatalogs for the WooCommerce stores in your list.

All of them: apify.com/autofacts

❓ FAQ

Do I need to configure the proxy? No — leave it on the default. Shopify limits requests per IP address, so the Actor rotates through Apify Proxy automatically, and sends a refused request again from another address. Turning the proxy off makes every store share one address and get refused together.

How fresh is the data? Every run reads each store live — its storefront, its catalog and its Shop app page — at the time of the run. Nothing is served from a cache, and scrapedUTC records when each row was read.

Is scraping these stores legal? Everything returned is published openly for anyone to read — no login, no paywall — by the store on its own storefront, or by the merchant on its Shop app page. Contacts are the addresses the store chose to publish, which can include a named person's where the store lists one. The Shop app is Shopify's consumer marketplace, and its terms restrict automated access; the Actor reads it by default, and useShopApp: false keeps a run to the stores' own storefronts. You are responsible for how you use the output, including under GDPR, CAN-SPAM and local marketing rules.

How many stores can I get? As many as maxItems allows and your filters leave. With a query or category, that is also as many as the Shop app's search has for the word — up to about 10,000 candidates a run; the run says so when the search runs out first. The Actor stops as soon as it has stored what you asked for.

Can I get results automatically? Yes. Schedule the Actor, or call it from the Apify API, or connect it to Make, Zapier, Slack, Google Sheets and the other Apify integrations. Results can also be pushed to a webhook when a run finishes.

Why are some fields empty? Not every store publishes everything. A store with no public email returns an empty contacts.emails rather than a guess. Empty means "not published", not "not checked".

Can you add a field or a filter? Yes — open an issue on the Actor and describe what you need.

🤖 Use with AI agents

This Actor is callable as a tool by any MCP-capable agent — Claude, Cursor, VS Code — or by your own code, with no wrapper and nothing extra to deploy.

Connect over MCP

https://mcp.apify.com?tools=autofacts/shopify-store-leads

In a client that reads an mcpServers configuration block:

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com?tools=autofacts/shopify-store-leads",
"headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
}
}
}

The agent reads this Actor's parameters and their descriptions straight from the input schema, and the hosted server infers the result field types from the dataset schema — so a model knows what to send and what comes back before it ever calls anything.

Or call the API directly

curl -X POST "https://api.apify.com/v2/acts/autofacts~shopify-store-leads/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"storeUrls": ["gorjana.com", "tentree.com", "ayvii.com"]}'

The response body is the dataset records described above.