# Shopify Store Leads Finder (`pintostudio/shopify-store-leads-finder`) Actor

Find live Shopify stores by keyword, at random, or by browsing a continuously refreshed index of millions of domains, then optionally enrich each result with contact emails, social profiles, and detected apps. Tip: set Max results to 5 for a fast, cheap test run before scaling up.

- **URL**: https://apify.com/pintostudio/shopify-store-leads-finder.md
- **Developed by:** [Pinto Studio](https://apify.com/pintostudio) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Shopify Store Leads Finder

**Find live Shopify stores by keyword, at random, or by browsing a continuously refreshed index of millions of domains — then optionally enrich every result with business contact emails, social profiles, and detected apps/tech stack, in the same run.**

No crawling setup, no proxies to manage, no separate enrichment tool to stitch on afterwards. Point this Actor at a keyword (or ask for a random sample, or just browse with no filter) and get back a clean, exportable list of Shopify domains ready for outreach, prospecting, or market research.

*Not affiliated with or endorsed by Shopify Inc. This Actor reads from a domain index that is rebuilt on a schedule — see "How freshness works" below.*

***

### Why this Actor

Most "find Shopify stores" workflows involve either scraping search engines (slow, blocked constantly, and full of non-Shopify noise) or buying a static, stale list that's out of date the day you get it. This Actor is backed by a domain index of **millions of live Shopify stores** that's rebuilt on a schedule, so every run reflects stores that are actually live *now* — and enrichment (contact emails, socials, apps) is one flag away instead of a second tool.

Typical uses:

- **Sales & agency prospecting** — build a keyword-targeted list of Shopify merchants ("coffee", "skincare", "pet supplies"...) and enrich it with contact emails in the same call, ready to load into your CRM or outreach tool.
- **Market & competitor research** — pull every live Shopify store in a niche to map the competitive landscape: who's out there, what apps they run, and how to reach them.
- **App & tool developers** — find your total addressable market of Shopify merchants matching a keyword, to size a launch or target a marketing campaign.
- **Investor & industry research** — use Random or Browse mode to pull an unbiased sample of live Shopify stores for category-level analysis, independent of any single keyword.
- **List building at scale** — up to 50,000 domains per run, with a reproducible seed for Random mode so you can extend a sample later without re-pulling stores you already have.

### How it works

1. **Find** — choose a mode: **Search** (match a keyword against store domains), **Random** (a reproducible random sample — reuse the seed to continue it later), or **Browse** (no filter at all, just the next page of the index).
2. **Enrich (optional)** — turn on any combination of business contact emails, social profile links, and detected apps/tech stack. Enrichment runs per-domain in parallel (tune with `enrichConcurrency`) and never fails the whole run: a domain whose enrichment lookup errors still comes back with an `...Error` field instead of being dropped.
3. **Export** — every result is one dataset row. Export as JSON, CSV, Excel, or pull it via the API — see "Run programmatically" below.

### What you get for each store

| Data point | Always included? | Input toggle |
|---|---|---|
| Domain | Yes, every row | — |
| Found-at timestamp | Yes, every row | — |
| Random-mode seed | Only in Random mode | — |
| Business contact emails | Only if enabled | `enrichContacts` |
| Social media profile links | Only if enabled | `enrichSocials` |
| Detected apps & tech stack | Only if enabled | `enrichApps` |

A domain whose enrichment lookup fails still produces a row with an `...Error` field instead of being dropped — a batch of thousands of domains is never derailed by one bad lookup.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | `search` | `random` | `browse` | `search` | Search: match a keyword against store domains. Random: a reproducible random sample. Browse: no filter, just the next page of the index. |
| `query` | string | — | Keyword to match against store domains, e.g. `"coffee"` or `"skincare"`. Required when Mode is Search. |
| `matchType` | `contains` | `startsWith` | `endsWith` | `exact` | `contains` | How to match the keyword against store domains (Search mode only). |
| `maxResults` | integer | 50 | Max domains to return this run (1-50,000, hard-capped server-side). **Tip: start with a small value like 5 for a fast, cheap test run before scaling up** — the examples below all use 5 for exactly that reason. |
| `seed` | string | — | Random mode only: reuse the seed returned by a previous Random-mode run to continue the same sample instead of getting a new one. |
| `enrichContacts` | boolean | `false` | Look up and attach business contact emails for each store found. |
| `enrichSocials` | boolean | `false` | Look up and attach social media profile links for each store found. |
| `enrichApps` | boolean | `false` | Look up and attach detected apps and tech stack for each store found. |
| `enrichConcurrency` | integer | 5 | How many stores to enrich in parallel (1-20). Higher is faster but heavier on the backend. |

Minimal input — a fast 5-result test run:

```json
{ "mode": "search", "query": "coffee", "maxResults": 5 }
```

Full-featured input — keyword search with all enrichment on, still capped at 5 for a quick preview run:

```json
{
  "mode": "search",
  "query": "skincare",
  "matchType": "contains",
  "maxResults": 5,
  "enrichContacts": true,
  "enrichSocials": true,
  "enrichApps": true,
  "enrichConcurrency": 5
}
```

Random sample, reproducible via seed:

```json
{ "mode": "random", "maxResults": 5, "enrichContacts": true }
```

Once you've confirmed the shape of the output on a small run, raise `maxResults` to pull the full list you need (up to 50,000 per run).

### Output example

One row per store. Here is a real row from a Search-mode run with all three enrichment toggles on (fields trimmed for length — `contacts` and `socials` cover 11 social networks each):

```json
{
  "domain": "coffeecups.co.uk",
  "foundAt": "2026-09-13T08:45:03.625Z",
  "contacts": {
    "domain": "coffeecups.co.uk",
    "emails": [],
    "phones": [],
    "socials": {
      "twitter": ["https://twitter.com/coffeecupstweet"],
      "instagram": ["https://instagram.com/coffeecups.co.uk"],
      "facebook": ["https://www.facebook.com/coffeecups.co.uk"],
      "tiktok": ["https://www.tiktok.com/@coffeecups.co.uk"]
    }
  },
  "socials": {
    "twitter": ["https://twitter.com/coffeecupstweet"],
    "instagram": ["https://instagram.com/coffeecups.co.uk"],
    "facebook": ["https://www.facebook.com/coffeecups.co.uk"],
    "tiktok": ["https://www.tiktok.com/@coffeecups.co.uk"]
  },
  "apps": [
    { "name": "Facebook & Instagram", "shopifyUrl": "https://apps.shopify.com/facebook", "url": "https://www.facebook.com/business" },
    { "name": "Google & YouTube", "shopifyUrl": "https://apps.shopify.com/google", "url": "https://www.google.com" },
    { "name": "Klaviyo: Email Marketing & SMS", "shopifyUrl": "https://apps.shopify.com/klaviyo-email-marketing", "url": "https://www.klaviyo.com" }
  ]
}
```

A store found without any enrichment toggles on (or in a plain Browse/Search run) returns just the two guaranteed fields:

```json
{ "domain": "coffeecups.co.uk", "foundAt": "2026-09-13T08:20:23.000Z" }
```

A store whose enrichment lookup fails still returns a row — with an `...Error` field instead of the data, so the run keeps going instead of stopping on one bad domain:

```json
{
  "domain": "fuglencoffee.no",
  "foundAt": "2026-09-13T08:29:48.364Z",
  "contactsError": "HTTP 400",
  "socialsError": "HTTP 400",
  "appsError": "HTTP 400"
}
```

### How freshness works

Results come from a domain index that's rebuilt on a schedule (not a live crawl triggered by your request) — see the freshness cadence on the Actor's listing page. Random mode's `seed` lets you deliberately continue the *same* sample across multiple runs, e.g. to page through a large random set without duplicates; leave it blank for a fresh sample every time.

### Pricing (pay-per-event)

This Actor is priced per event via `Actor.charge()`. The exact USD price for each event is configured in the Apify Console (Publication -> Monetization -> Pay per event), not in this document — the table below shows what triggers each charge:

| Event | Fires |
|---|---|
| `actor-start` | Once per run |
| `store-found` | Per domain returned (before enrichment) |
| `store-enriched` | Per domain that had at least one enrichment field requested |

Running a small `maxResults: 5` test costs a small fraction of a full run — use it to confirm the output shape before scaling up to thousands of domains.

### Getting started

1. Open the **Input** tab and pick a **Mode** (Search, Random, or Browse).
2. If using Search, enter a **Keyword** and (optionally) a match type.
3. Set **Max results** — start at **5** for a fast, cheap first look at the output.
4. Toggle on any enrichment fields you want (contacts, socials, apps).
5. Click **Start**. Once you've checked the shape of the results, raise Max results and run again for your full list.
6. Open the **Dataset** tab (or the **Output** tab) to view or export the results as JSON, CSV, Excel, or via the API.

### Run programmatically via the API

```bash
curl "https://api.apify.com/v2/acts/pintostudio~shopify-store-leads-finder/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \\
  -H "Content-Type: application/json" \\
  -d '{ "mode": "search", "query": "coffee", "maxResults": 5 }'
```

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });

const run = await client.actor('pintostudio/shopify-store-leads-finder').call({
  mode: 'search',
  query: 'coffee',
  maxResults: 5,
  enrichContacts: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")

run = client.actor("pintostudio/shopify-store-leads-finder").call(run_input={
    "mode": "search",
    "query": "coffee",
    "maxResults": 5,
    "enrichContacts": True,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

This Actor also ships a Live-view/OpenAPI web-server schema, so it can be called as a standalone REST API — see the **API** tab on this Actor's page for the full request/response reference and a ready-to-run OpenAPI spec.

### Frequently asked questions

**Do I need a Shopify account or API access to the stores I'm searching?**
No. Everything comes from the domain index and public enrichment lookups — no login, no partnership, no API key for the stores you're finding.

**Why does `maxResults` default so low, and why do the examples use 5?**
So a first test run is fast and cheap. Confirm the output looks right on a small run, then raise `maxResults` (up to 50,000) for your real pull.

**What happens if enrichment fails for a domain?**
You still get the row back, with an `...Error` field (e.g. `contactsError`) instead of the data — the run doesn't stop.

**Can I get the exact same random sample twice?**
Yes — use Random mode once, note the `seed` value on the returned rows, then pass that same `seed` on a later run to continue the identical sample.

**Can I combine Search mode with a very specific match type?**
Yes — set `matchType` to `exact`, `startsWith`, or `endsWith` instead of the default `contains` for tighter keyword matching.

**Can I use this for cold outreach lead lists?**
Yes — Search or Random mode with `enrichContacts` and `enrichSocials` on is the most common setup for building a keyword- or category-targeted outreach list.

### Notes & limitations

- Results reflect the domain index's last scheduled refresh, not a live crawl at request time.
- Enrichment (contacts/socials/apps) is looked up per-domain in parallel and priced per successful enrichment — a domain that fails enrichment is not charged for that event.
- Each run is capped at 50,000 domains; queue additional runs, or Tasks, for larger pulls.
- No Shopify account, API key, or store access is required from you — that's the whole point of this tool.

***

### Shopify store finder, lead generator & Shopify B2B prospecting tool — in one Actor

Looking for a **Shopify store finder**, a **Shopify lead generation tool**, a way to **find Shopify stores by keyword**, or a **Shopify store list builder** for prospecting? This Actor is built to answer exactly that in a single run. It works as a **Shopify store scraper** for sales and agency teams, a **Shopify merchant database** and **Shopify email finder** for B2B outreach, and a **Shopify competitor research tool** for market mapping — covering keyword search, random sampling, unfiltered browsing, and optional one-pass enrichment with business contact emails, social media profiles, and detected apps/tech stack for any live Shopify-powered store. Common searches this Actor answers: "find Shopify stores by keyword", "Shopify store list for sales prospecting", "get Shopify store emails", "Shopify merchant leads API", "bulk Shopify domain finder", and "Shopify store scraper for lead generation". Whether you need a quick 5-result preview or a scheduled Task pulling thousands of fresh leads every week, this Actor turns a keyword (or a random sample, or an unfiltered browse) into a structured, exportable list of live Shopify stores — ready for a CRM, a spreadsheet, or your own data warehouse via the Apify API, JSON, CSV, or Excel export.

# Actor input Schema

## `mode` (type: `string`):

Search: match a keyword against store domains. Random: a reproducible random sample — reuse the returned seed to page through it. Browse: paginate the full index with no filter.

## `query` (type: `string`):

Text to match against store domains, e.g. "coffee" or "skincare". Required when Mode is Search.

## `matchType` (type: `string`):

How to match the keyword against store domains: substring match, prefix match, suffix match, or an exact domain match.

## `maxResults` (type: `integer`):

Hard-capped server-side regardless of this value — see the Actor's environment configuration.

## `seed` (type: `string`):

Reuse the seed returned by a previous Random-mode run to continue the same random sample from where you left off.

## `enrichContacts` (type: `boolean`):

Look up and attach business contact emails for each store found. Costs an extra store-enriched event per store — see Pricing in the README.

## `enrichSocials` (type: `boolean`):

Look up and attach social media profile links (Instagram, Facebook, TikTok, etc.) for each store found. Costs an extra store-enriched event per store.

## `enrichApps` (type: `boolean`):

Look up and attach detected apps and tech stack (e.g. Klaviyo, Recharge) for each store found. Costs an extra store-enriched event per store.

## `enrichConcurrency` (type: `integer`):

How many stores to enrich in parallel. Higher = faster but heavier on the backend.

## Actor input object example

```json
{
  "mode": "search",
  "query": "coffee",
  "matchType": "contains",
  "maxResults": 50,
  "enrichContacts": false,
  "enrichSocials": false,
  "enrichApps": false,
  "enrichConcurrency": 5
}
```

# Actor output Schema

## `leads` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "search",
    "query": "coffee"
};

// Run the Actor and wait for it to finish
const run = await client.actor("pintostudio/shopify-store-leads-finder").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "search",
    "query": "coffee",
}

# Run the Actor and wait for it to finish
run = client.actor("pintostudio/shopify-store-leads-finder").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "search",
  "query": "coffee"
}' |
apify call pintostudio/shopify-store-leads-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pintostudio/shopify-store-leads-finder"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/6Nz7fuHXeQvhjatMS/builds/Dy3NZqC4dK2Tn2oNu/openapi.json
