# Shopify Email Scraper (Cheap) (`data_api/shopify-email-scraper-cheap`) Actor

Shopify website scraper that searches two store databases and returns email and company contact data, filtered by country, ZIP code, employee count, and revenue for Shopify merchant prospecting.

- **URL**: https://apify.com/data\_api/shopify-email-scraper-cheap.md
- **Developed by:** [Data API](https://apify.com/data_api) (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 $0.99 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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 Email Scraper

![Shopify Store Email Scraper](cover.jpg)

Building a sales list of Shopify stores by hand means opening hundreds of storefronts, hunting for a contact email, and copying revenue and headcount guesses into a spreadsheet. This scraper skips all of that. Tell it the kind of store you want by keyword, country, postal code, team size, or revenue band, and it returns clean rows with the store name, contact email, phone, website, location, and revenue. Pull a short test list or a few thousand records, then export the whole thing as JSON, CSV, or Excel.

### What you get

Every store comes back as one tidy row, and the columns stay the same from the first record to the last, so a missing phone or city shows up as an empty value rather than shifting your data sideways. Each row carries:

- **Contact details** — `storeName`, `contactEmail`, `contactPhone`, `storeUrl`
- **Location** — `cityName`, `regionName`, `postalCode`, `countryCode`
- **Company size** — `staffCount`, `annualRevenue`

### Quick start

1. Press **Try for free** to open the input form.
2. Add a few words to **Store name or keyword search** (for example `coffee` or `skincare`), or leave it empty to match every store.
3. Optionally narrow things down with country, postal code, headcount, or revenue filters.
4. Set **How many records to return**, press **Start**, and download the results as JSON, CSV, or Excel once the run finishes.

![How it works](how-it-works.jpg)

### Use cases

- **B2B outreach** — pull a list of Shopify merchants that fit your ideal customer and email or call them straight away
- **Agency lead generation** — surface stores that could use design, SEO, fulfilment, or paid-ads help
- **Market sizing** — count and compare stores across countries, postal areas, and revenue bands
- **Partner sourcing** — track down wholesale, dropship, or affiliate prospects in a niche you choose
- **Competitor mapping** — see which stores sit near your own revenue and headcount range
- **CRM enrichment** — top up existing records with fresh emails, phones, and revenue figures

### Input

Every field is optional. Leave them all blank to return stores in default order up to your `resultsLimit`.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `storeKeywords` | array of strings | No | Words to match inside store names. Case-insensitive partial match; a store is kept if it matches any term. |
| `countryNames` | array of strings | No | Full country names to include (e.g. `Germany`, `Australia`). A store is kept if it sits in any listed country. |
| `postalCodes` | array of strings | No | Postal or ZIP codes to include. A store is kept if it matches any code supplied. |
| `minStaffCount` | integer | No | Lower bound on team size. Sizes round to bands: `1`, `10`, `100`, `1000`, `10000`, `100000`. |
| `maxStaffCount` | integer | No | Upper bound on team size. |
| `minAnnualRevenue` | number | No | Lowest yearly revenue in USD to include. |
| `maxAnnualRevenue` | number | No | Highest yearly revenue in USD to include. |
| `resultsLimit` | integer | No | How many rows to return across both databases. Default `50`. |
| `sortField` | string | No | Column to order by: `Company`, `Country`, `Employees`, `Sales Revenue USD`, or `Zip`. Default unsorted. |
| `sortDirection` | string | No | Order direction, `asc` or `desc`. Applies only when `sortField` is set. Default `asc`. |

#### Example input

```json
{
    "storeKeywords": ["skincare", "coffee"],
    "countryNames": ["Germany", "Australia"],
    "postalCodes": [],
    "minStaffCount": 5,
    "maxStaffCount": 250,
    "minAnnualRevenue": 250000,
    "maxAnnualRevenue": 10000000,
    "resultsLimit": 200,
    "sortField": "Sales Revenue USD",
    "sortDirection": "desc"
}
```

### Output

Each row is one Shopify store with its contact details, location, and size. Results export as JSON, CSV, or Excel.

#### Example output

```json
{
    "storeName": "Northwind Coffee Roasters",
    "contactEmail": "hello@northwindroasters.com",
    "storeUrl": "https://northwindroasters.com",
    "countryCode": "DE",
    "postalCode": "10115",
    "staffCount": 10,
    "annualRevenue": 1850000,
    "contactPhone": "+49 30 5551234",
    "cityName": "Berlin",
    "regionName": "Berlin"
}
```

#### Output fields

| Field | Type | Description |
|-------|------|-------------|
| `storeName` | string | Name of the store or company |
| `contactEmail` | string | Email address listed for reaching the store |
| `storeUrl` | string | Web address of the Shopify storefront |
| `countryCode` | string | Two-letter ISO country code such as `US`, `GB`, `CA` |
| `postalCode` | string | Postal or ZIP code on file |
| `staffCount` | integer | Rough team size, rounded into bands: 1, 10, 100, 1000, 10000, 100000 |
| `annualRevenue` | number | Yearly sales figure in US dollars |
| `contactPhone` | string | Phone number on file, when published |
| `cityName` | string | City the store operates from, when known |
| `regionName` | string | State, province, or region, when known |

### Tips for best results

- **Start with a small `resultsLimit`.** Run 20 to 50 rows first to confirm the columns fit your pipeline, then raise the cap for the full pull.
- **Combine filters to sharpen the list.** Pairing a keyword with a country or revenue band gives a tighter, more useful set than any single filter alone.
- **Match country names to their full form.** Use `United States` or `United Kingdom` rather than abbreviations so the country lookup resolves cleanly.
- **Empty fields are normal.** Not every store publishes a phone, city, or region, so those columns can be blank even on a good match.
- **Got zero rows?** The run log points to which filter is too tight. Loosen the headcount or revenue range, or check the spelling of your keywords and countries.

### How can I use Shopify store data?

**How can I use the Shopify Store Email Scraper to build a B2B prospect list?**
Set a keyword that fits your niche, add the countries you sell into, and set a revenue band that matches your ideal customer. Each row comes back with `storeName`, `contactEmail`, `contactPhone`, and `storeUrl`, so you can drop the export straight into your outreach tool and start contacting merchants the same day.

**How can I find Shopify store emails by country or postal code?**
Fill in `countryNames` with the markets you want, or `postalCodes` to zoom into a city or region. The scraper keeps any store that matches and returns its contact email alongside its location, which is handy for local campaigns or territory planning for a sales team.

**How can I enrich my CRM with Shopify store revenue and size data?**
Search by keyword or location, then read the `staffCount` and `annualRevenue` columns on every row. Matching those figures back to your existing accounts tells you which stores fit your target profile, so you can prioritise the ones worth a real conversation.

**How can I research a Shopify niche or compare competitors?**
Run a keyword search with no revenue filter to capture the whole field, then sort by `Sales Revenue USD` or headcount to see how stores stack up. Counting rows by country or postal code gives you a quick read on where a niche is concentrated.

### Is it legal to scrape data?

Our actors are ethical and do not extract any private user data, such as email addresses or private contact information. They only extract what the user has chosen to share publicly. We therefore believe that our actors, when used for ethical purposes by Apify users, are safe.

However, you should be aware that your results could contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

You can also read Apify's blog post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

### Support

Questions, feature requests, or a field you'd like added? Reach out at <data.apify@proton.me> and we'll get back to you.

# Actor input Schema

## `storeKeywords` (type: `array`):

Type one or more words to look for inside store names. Matching ignores case and works on partial words, and a record is kept when it matches any term you list.

## `countryNames` (type: `array`):

List the countries you care about by full name, for example Germany, Australia, or Ireland. A store is kept if it sits in any country on your list. Leave it blank to keep every country.

## `postalCodes` (type: `array`):

Restrict results to one or more postal or ZIP codes. A store is kept if it matches any code you supply. Skip this field to ignore location entirely.

## `minStaffCount` (type: `integer`):

Drop any store whose team is smaller than this number. Leave blank to set no lower bound.

## `maxStaffCount` (type: `integer`):

Drop any store whose team is bigger than this number. Leave blank to set no upper bound.

## `minAnnualRevenue` (type: `number`):

Keep only stores that earn at least this much per year in US dollars. Leave blank to set no lower bound.

## `maxAnnualRevenue` (type: `number`):

Keep only stores that earn at most this much per year in US dollars. Leave blank to set no upper bound.

## `resultsLimit` (type: `integer`):

Caps the number of rows pulled across both store databases. Rows are fetched in batches of 100. Default `50`.

## `sortField` (type: `string`):

Pick the column used to order the output. Ordering happens inside each database on its own.

## `sortDirection` (type: `string`):

Choose whether the chosen column climbs or falls. This is ignored unless an order column is set.

## Actor input object example

```json
{
  "storeKeywords": [
    "skincare",
    "coffee"
  ],
  "countryNames": [
    "Germany",
    "Australia"
  ],
  "postalCodes": [
    "94107",
    "SW1A"
  ],
  "minStaffCount": 5,
  "maxStaffCount": 250,
  "minAnnualRevenue": 250000,
  "maxAnnualRevenue": 10000000,
  "resultsLimit": 50,
  "sortField": "",
  "sortDirection": "asc"
}
```

# 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 = {
    "storeKeywords": [
        "skincare",
        "coffee"
    ],
    "resultsLimit": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("data_api/shopify-email-scraper-cheap").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 = {
    "storeKeywords": [
        "skincare",
        "coffee",
    ],
    "resultsLimit": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("data_api/shopify-email-scraper-cheap").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 '{
  "storeKeywords": [
    "skincare",
    "coffee"
  ],
  "resultsLimit": 50
}' |
apify call data_api/shopify-email-scraper-cheap --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,data_api/shopify-email-scraper-cheap"
        }
    }
}

```

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/WrGPHFNqy30UMhZA2/builds/dWLvxAXdMl61SQSLU/openapi.json
