# Shopify Store Leads & Emails (`sandy_yclept/shopify-store-leads`) Actor

Find Shopify stores by product keyword and country, and get each store's email, phone and socials from its own website, MX-checked, with its currency, catalogue size and shipping countries. This Actor charges only for stores where an email is found; the Google search is billed per page.

- **URL**: https://apify.com/sandy\_yclept/shopify-store-leads.md
- **Developed by:** [Rafal Sav](https://apify.com/sandy_yclept) (community)
- **Categories:** Lead generation, E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 store leads

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Shopify Store Leads & Emails do?

**Shopify Store Leads & Emails** finds **Shopify stores by what they sell** and gets **each store's email, phone and social profiles from its own website**. Type a product keyword — `coffee roasters`, `candles`, `Naturkosmetik` — and a country, and you get one record per store: its name and website, the **email it answers**, checked for a working mail server, its phones and socials, and what the store's own settings say about it — **country, city, currency, number of products and the countries it ships to**.

You **pay only for stores where an email is found**. A store whose website has no email, or only someone else's address (the theme developer, an app vendor, the agency that built it), costs nothing.

It runs on the [Apify platform](https://apify.com): API access, scheduling, integrations (Make, Zapier, n8n, Google Sheets) and run monitoring included.

### Why use it?

- **Real Shopify stores, checked one by one.** Stores are found on Google with the line Shopify themes print in their footer, and every result is asked for the `/meta.json` a Shopify storefront publishes: a domain is kept only when it answers as a Shopify store. Marketplaces, blogs and directories never reach your list.
- **Most stores come back with an email.** On 586 Shopify stores found this way for 35 keywords in five countries, **582 (99.3%)** were read and **466 (80%)** gave a usable email (September 2026, details below).
- **The email is the store's own.** An address counts only when it is on the store's domain, on a second domain carrying its name, or a personal mailbox the owner uses (Gmail, Outlook, T-Online…). App vendors, theme developers, web agencies and payment providers are returned for reference but **never billed and never picked as `best_email`**.
- **Store facts included.** Currency, catalogue size and shipping countries come from the store's own settings — useful to size a lead before you write.
- **Emails are checked for a working mail server.** A domain that accepts no mail is flagged `valid_mx: false` and never billed.

### Use cases

- **Outreach to e-commerce brands** — agencies, app developers, 3PLs, packaging and payment providers selling to Shopify merchants.
- **Supplier and wholesale prospecting** — every coffee roaster or candle maker in a country, with an inbox.
- **Market research** — how many stores sell a product in a market, in which currency, how big their catalogues are.

### How to use it

1. Enter one or more **Product keywords** (one per line) and a **Country**.
2. Set **Google result pages per keyword** — about 8 Shopify stores a page, about 6 of them based in the country — and it caps what the search costs.
3. Click **Start**. Stores are read as soon as Google returns them; download the results as JSON, CSV, Excel or HTML.

### Input

| Field | What it does |
|---|---|
| Product keywords | What the stores sell. Each keyword is searched on Google with `"powered by shopify"`. |
| Country | Google is searched as from this country. |
| Which stores of that country | Based there (default), based there or shipping there, or any store the search finds. |
| Google result pages per keyword | Pages of Google results per keyword (default 2, about 8 Shopify stores a page). |
| Minimum published products | Skip empty and demo stores (default 1). |
| Max contact subpages | How many contact-like pages to read per store (default 5). |
| Validate emails | Check each email's domain for a mail server (on by default). |
| JavaScript rendering | `auto` re-reads a store in a browser when no usable email was found without one; needs 2048 MB of memory. |

### Output

One record per store:

```json
{
  "name": "Clive Coffee",
  "website": "https://clivecoffee.com/",
  "best_email": "hello@clivecoffee.com",
  "emails": [
    {"email": "hello@clivecoffee.com", "valid_mx": true, "role": true, "confidence": 0.85, "kind": "own"},
    {"email": "support@clivecoffee.com", "valid_mx": true, "role": true, "confidence": 0.85, "kind": "own"}
  ],
  "phones": ["+18885575320"],
  "socials": {
    "facebook": ["https://facebook.com/clivecoffeepdx"],
    "instagram": ["https://instagram.com/clivecoffee"]
  },
  "country_code": "US",
  "city": "Portland",
  "currency": "USD",
  "products_count": 1458,
  "ships_to": ["*", "CA", "US"],
  "myshopify_domain": "clivecoffee.myshopify.com",
  "status": "ok",
  "billed": true,
  "search_string": "coffee",
  "rank": 15
}
```

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

| Field | Meaning |
|---|---|
| `best_email` | The store's own address to write to: a named person on its domain first, then a contact inbox, then a personal mailbox. Empty when none was found. |
| `emails` | Every address found, each with `valid_mx`, `role`, `confidence` and `kind`: `own`, `related` (a domain carrying the store's name), `free_mail` or `other` (someone else's — never billed). |
| `phones`, `socials` | Phone numbers in E.164 and social profile links from the store's website. |
| `company` | For stores with a German legal notice (Impressum): `company`, `legal_form`, `representatives`, `vat_id`, `register_court`, `register_number` and `address`; `null` without one. |
| `country_code`, `city`, `province` | Where the store says it is based. |
| `currency`, `products_count`, `ships_to` | From the store's own settings; `*` in `ships_to` means the rest of the world. |
| `status` | `ok`, `no_contacts` (the store publishes no email, only a form) or `unreachable`. |
| `billed` | Whether this store was charged. |
| `search_string`, `rank` | The keyword that found it, and its position on the Google results page. |

### Accuracy

On **September 25, 2026** we searched Google for `"powered by shopify"` with 35 product keywords — coffee, candles, activewear, dog treats, jewelry, Naturkosmetik, gin, maple syrup and more — as from the US, UK, Germany, Australia and Canada: 604 domains. Their `/meta.json` showed 586 Shopify stores. In one cloud run of this engine:

| Of 586 Shopify stores | |
|---|---|
| Read | **582 (99.3%)** |
| Usable email (own domain, related domain or personal mailbox) | **466 (80%)** |

Every `best_email` of an earlier batch of 94 billed stores was reviewed: 90 were the store's own — on its domain, on its brand's second domain, or a mailbox named after it — and the other 4 were malformed addresses (`%20info@`, `nfo@`, a German privacy-policy template that glues "an" to the address) — three extraction bugs, fixed before this Actor was published; all four now come out right.

On the keywords: a bare keyword gives about 12-17 stores over two result pages (81% of the result domains are Shopify stores), and each variant adds 10-17 more (96% Shopify): `coffee` plus five variants found about 95 stores.

### How much does it cost?

Two things are paid, both only for what is delivered:

- **Store with email — $0.004** (~$4 per 1,000), charged by this Actor for each store whose website gave a usable email. Stores without an email, or with only someone else's address: **$0**. Phones, socials and the store facts are included.
- **The Google search.** It is run by [Google Search Results Scraper](https://apify.com/apify/google-search-scraper) in a separate run on your account, which bills each results page — $4.50 per 1,000 pages on the Free plan, $2.50 on Starter. A page gives about 8 Shopify stores, 6 of them based in the country searched (71% on 22 searches in five countries; 49% in Canada, where US stores rank high). Its paid extras (AI answers, lead enrichment, page contents) are all switched off. That Actor needs a maximum cost of at least $0.50 per run, so keep $0.50 of credit available.

100 coffee stores in the US cost about **$0.08** for the search plus **about $0.32** for the emails (80 stores with an email).

### Tips

- **Use several narrow keywords** rather than more pages of one: `espresso`, `cold brew` and `coffee roasters` find new stores where page 3 of `coffee` drifts off-topic.
- **Write keywords in the market's language** for non-English countries: `Naturkosmetik`, `Kaffee`, `Hundefutter`.
- **Only Shopify stores that keep the "Powered by Shopify" footer are found.** Most small and mid-size stores do; many large brands remove it.
- **Some stores publish only a contact form.** They come back `no_contacts`, unbilled, with their phones and socials when they have them.

### FAQ

#### Why does a store have no email?

Check `status`. `no_contacts`: the store publishes no email on its homepage or contact pages — often only a contact form. Shopify's own policy pages (`/policies/…`) are closed to crawlers by every store's robots.txt, which this Actor respects. `unreachable`: the store refused the request. None of these are billed.

#### Why is an address in `emails` but not `best_email`?

It is on someone else's domain (`kind: other`): an app vendor, a theme developer, the agency that built the store, a parent company. It is returned so you can see it, but never billed and never chosen as the address to write to.

#### Can I give it a list of store URLs instead?

Use the [Website Contact & Email Scraper](https://apify.com/sandy_yclept/website-contact-email-scraper) — same engine, one record per website, priced per contact.

#### Is scraping this data legal?

Store websites are public, and this Actor respects `robots.txt` and rate-limits its requests. What you do with the data is your responsibility: under GDPR you are the data controller, you need a lawful basis for outreach, some countries restrict unsolicited commercial email (for example § 7 UWG in Germany), and you must honour opt-outs.

### Related Actors

- [Website Contact & Email Scraper](https://apify.com/sandy_yclept/website-contact-email-scraper) — emails, phone numbers and social profiles from any list of websites, priced per contact.
- [Impressum Email Scraper](https://apify.com/sandy_yclept/impressum-email-scraper) — the same for German websites: the Impressum read first, `DE` phone numbers, the authorities a legal page must name left out.
- [Google Maps Email Extractor](https://apify.com/sandy_yclept/google-maps-email-extractor) — local businesses from a Google Maps search, each with the email from its own website.
- [No Website Leads](https://apify.com/sandy_yclept/no-website-leads) — businesses on Google Maps without a real website, for web design agencies.

### Disclaimer

This Actor is a **tool**. You are the data controller for any personal data you collect and are responsible for complying with GDPR and local marketing law, the target sites' Terms of Service and robots.txt. It does not build or sell contact databases. It is not affiliated with Shopify.

### Support

Found a store where an email was missed or the wrong one was picked? Open an issue on the **Issues** tab — accuracy reports shape the roadmap directly.

# Actor input Schema

## `keywords` (type: `array`):

What the stores sell, one keyword per line: "coffee", "candles", "Naturkosmetik". Each keyword is searched on Google together with the line Shopify themes print in their footer, "powered by shopify". Variants find more stores: "espresso", "cold brew" and "coffee roasters" each add 10-17 new ones to "coffee".

## `country` (type: `string`):

Google is searched as from this country, and stores are kept by where they are based (see the next field).

## `storeLocation` (type: `string`):

Based there (default): stores whose own settings give that country as their address. Based there or shipping there: also stores elsewhere that ship to it, including those shipping worldwide. Any: every Shopify store the search finds.

## `pagesPerKeyword` (type: `integer`):

How many pages of Google results to read for each keyword. A page gives about 8 Shopify stores, about 6 of them based in the country searched; the Google search bills every page it reads, so this also caps what the search costs. Past the second page the stores drift away from narrow keywords - a new keyword usually finds more.

## `minProducts` (type: `integer`):

Skip stores with fewer products on sale. 1 (default) drops empty stores and demos; 0 keeps every store.

## `maxContactPages` (type: `integer`):

How many contact-like subpages (/pages/contact, /pages/about, an imprint) to read on each store, on top of its homepage. Set to 0 to read the homepage only. Shopify's own policy pages are closed to crawlers by every store's robots.txt.

## `validateEmails` (type: `boolean`):

Check each email's domain for MX records and attach a confidence score. An address whose domain accepts no mail is returned but never billed.

## `includeSocials` (type: `boolean`):

Extract Instagram, Facebook, TikTok, YouTube, X/Twitter and LinkedIn profile links from each store (share/intent URLs are filtered out). Included in the price of a store; a store with only socials is not billed.

## `renderJs` (type: `string`):

Load pages in a real browser to reach contacts that are rendered by JavaScript. Off (default) is the fastest and cheapest. Auto scans without a browser first and only re-crawls a site in the browser when nothing was found — best accuracy/cost ratio. On always uses the browser. Auto and On require the run memory to be at least 2048 MB. Below 1024 MB the browser is not started and the run says so.

## `proxyConfiguration` (type: `object`):

Optional proxy for fetching pages. Apify Proxy's datacenter IPs are included in every Apify plan, the Free plan too; residential proxies are billed separately. Left disabled, the Actor connects directly, and retries sites that refuse it through Apify Proxy (see below).

## `proxyFallback` (type: `boolean`):

Every cloud run has a datacenter IP address, and some sites turn those away. A site that refuses or drops the direct connection is retried once through Apify Proxy's datacenter IPs (included in every Apify plan, the Free plan too), then once more directly. Sites that answer directly never go through the proxy, and robots.txt is respected either way. Has no effect when a proxy is configured above.

## Actor input object example

```json
{
  "keywords": [
    "coffee roasters",
    "espresso"
  ],
  "country": "US",
  "storeLocation": "based",
  "pagesPerKeyword": 2,
  "minProducts": 1,
  "maxContactPages": 5,
  "validateEmails": true,
  "includeSocials": true,
  "renderJs": "off",
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "proxyFallback": true
}
```

# Actor output Schema

## `results` (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 = {
    "keywords": [
        "coffee roasters"
    ],
    "country": "US",
    "pagesPerKeyword": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("sandy_yclept/shopify-store-leads").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 = {
    "keywords": ["coffee roasters"],
    "country": "US",
    "pagesPerKeyword": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("sandy_yclept/shopify-store-leads").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 '{
  "keywords": [
    "coffee roasters"
  ],
  "country": "US",
  "pagesPerKeyword": 2
}' |
apify call sandy_yclept/shopify-store-leads --silent --output-dataset

```

## MCP server setup

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

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/IvH6FSinEzyoHWvrW/builds/ROskyUYqLy1cFKjvB/openapi.json
