Finding and Qualifying Shopify Stores in a Niche Before You Cold-Email Them
Key Takeaways
Why not just scrape every Shopify store and filter later? Volume, not accuracy — there are millions of Shopify stores, and most are inactive, out of your target niche, or don't want the pitch you're sending. Filtering at the source (category, location, product count) is cheaper than pulling everything and discarding 95% of it downstream.
What's the difference between a store lead and a B2B lead? A store lead (name, domain, category, contact channels) tells you who to contact. A B2B enrichment pass (owner/founder name, detected apps, wholesale flag) tells you what to say — whether they'd plausibly need your product based on what's already installed or missing on their stack.
How do you avoid emailing a dead or abandoned store? Cross-check the store's own sample product listings for recent activity signals (in-stock items, review counts, recent product additions) before it enters your outreach list — a storefront with no reviews and stale inventory is a wasted send.
Step 1: Find Stores in Your Niche
Start narrow, not broad. The Shopify Store Leads Scraper takes a category (14 category enums covering things like home goods, apparel, beauty) or a free-text query, plus a storeLocation filter — region codes like NORTH_AMERICA or EUROPE, or a specific country — so you're not pulling a global list you'll filter by hand later:
{
"name": "Café Britt",
"websiteUrl": "https://www.cafebritt.com",
"address": { "city": "Miami", "zone": "Florida", "country": "US" },
"contacts": [
{ "method": "email", "target": "info@britt.com" },
{ "method": "phone", "target": "1-800-462-7488" },
{ "method": "instagram", "target": "https://www.instagram.com/cafebritt_us" }
],
"rating": 4.9,
"totalProductReviews": 699
}
Two fields here are your first-pass quality filter before you spend anything on enrichment: totalProductReviews (a store with 699 reviews is clearly live and selling; one with zero is a coin flip) and rating. Sort by review count, keep the top slice, discard the long tail of near-empty stores that technically match your category filter but aren't real prospects.
Step 2: Enrich With Ownership and Stack Data
A store name and a contact email tell you who to email — they don't tell you what to say. This is where a second pass earns its keep. Feed the domains from step one into the Shopify Store B2B Leads Finder, which resolves each domain to founder/owner name, detected app stack, and a wholesale flag:
{
"domain": "candlebliss.com",
"storeName": "Candle Bliss",
"contactEmail": "hello@candlebliss.com",
"ownerFounderName": "Jessica Hartwell",
"estimatedProductCount": 112,
"storeNiche": "Home & Garden",
"hasWholesale": true,
"detectedApps": ["Klaviyo", "Judge.me", "Afterpay"]
}
detectedApps is the highest-leverage field for outreach personalization: if you're selling an email-marketing tool and the store already has Klaviyo installed, that's not a lead — pitch something else, or skip it. If it's missing entirely from a store this size, that's a genuinely relevant opening line, not a generic "hey I noticed your store" cold email.
Step 3: Verify a Real, Reachable Contact
Store-level contact fields are sometimes a generic info@ inbox that nobody reads, or missing entirely for stores that don't publish contact info in their theme footer. Before a domain enters your outreach tool, run it through the Website Email, Phone & Social Media Finder, which does a three-pass crawl — homepage, then contact/about/team pages, then footer links — specifically to catch contacts the store-leads pass missed:
{
"url": "https://candlebliss.com",
"emails": ["hello@candlebliss.com", "press@candlebliss.com"],
"phones": ["+1 (512) 847-3920"],
"socials": ["https://www.linkedin.com/company/candle-bliss"]
}
Getting a LinkedIn URL out of this pass matters more than it looks — if the founder-name field from step two is populated, a matched LinkedIn company page lets you route the message to a named person on LinkedIn instead of a generic inbox, which meaningfully changes response rates for cold outreach.
Putting the Three Passes Together
async function buildQualifiedList(category, location) {
const stores = await runActor("shopify-store-leads-scraper", { category, storeLocation: location });
const active = stores.filter(s => s.totalProductReviews > 10);
const domains = active.map(s => new URL(s.websiteUrl).hostname);
const enriched = await runActor("shopify-b2b-leads-finder", { inputUrls: domains });
const contacts = await runActor("website-contact-finder", { urls: domains });
return enriched.map(store => ({
...store,
verifiedContacts: contacts.find(c => c.url.includes(store.domain)),
}));
}
Each pass narrows the list further — the point isn't to end up with the largest possible list, it's to end up with a list where every row has a real reason to be contacted and a real inbox to reach.
FAQ
Do you need to enrich every store you find, or just the top matches?
Just the top matches — enrichment is the expensive step relative to the initial category pull, so filter hard on totalProductReviews and rating first, then only run steps two and three on the slice you'd actually email.
What if a store has no public contact info at all? Treat it as disqualified rather than chasing a generic contact form — a store actively hiding contact info is a low-response prospect regardless of how well it matches your niche.
For a similar three-pass qualify-then-contact pattern applied to a completely different vertical, see Building the Clay Playbook: Enriching Leads With a Custom HTTP Call, or browse ParseBird's e-commerce actors for adjacent lead sources.