# Keyword Shop Finder — Ecommerce Leads & Retailers by Product (`your_data_miner/keyword-shop-finder`) Actor

Find online stores and retailers that sell a product, in any country and language. Enter a product keyword, get independent e-commerce shops with business email, platform (Shopify, WooCommerce…) and domain age. Marketplaces and blogs filtered out. Pay only per verified shop.

- **URL**: https://apify.com/your_data_miner/keyword-shop-finder.md
- **Developed by:** [Deep Mind](https://apify.com/your_data_miner) (community)
- **Categories:** Lead generation, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.00 / 1,000 verified shops

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/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

**Find online stores and retailers that sell a specific product — in any country and language — with a verified business email for each shop.**

Enter a **product keyword** (`cork yoga mat`, `arnés para perro`, `machine à expresso manuelle`) and a **market** (`us/en`, `de/de`, `fr/fr`). Keyword Shop Finder searches Google for that product, opens every result, keeps only **independent online shops that actually sell it**, and finds their **business email**, **e-commerce platform** and **domain age**. You get a clean list of **e-commerce leads**, not a pile of links: marketplaces, blogs, price comparators and off-topic stores are filtered out.

Built for anyone who **sells to online stores**: brands and manufacturers looking for retailers and stockists, wholesalers and distributors, dropshipping and fulfilment platforms recruiting merchants, marketplaces onboarding sellers, agencies, SaaS and logistics vendors prospecting e-commerce brands.

### What does Keyword Shop Finder do?

- **Finds online stores by product**, not by platform or category: "who sells *gooseneck kettles* in the US", "who sells *yoga mats* in Germany".
- **Works in any Google country and language** — `de/de`, `fr/fr`, `es/es`, `it/it`, `nl/nl`, `pl/pl`, `br/pt`, `mx/es` and so on. Keywords are searched in the market's own language.
- **Works on any shop platform** — Shopify, WooCommerce, Magento, PrestaShop, OpenCart, BigCommerce, Squarespace and custom builds.
- **Checks every site** with an AI classifier: is it a real shop, does it sell *this* product, who is the merchant behind an affiliate page.
- **Finds a business email on the shop's own pages** (contact, imprint, about) and checks its mail server.
- **Adds the domain registration date**, so you can spot new shops that are still choosing suppliers.
- **Charges only for verified shops.** Uncertain and rejected sites are delivered free.

The Apify platform adds the rest: API access, scheduled runs, integrations (Google Sheets, Zapier, Make, n8n, webhooks), export to CSV/Excel/JSON, and access for AI agents through the Apify MCP server.

### What data do you get?

One row per unique shop domain:

| Field | Meaning |
|---|---|
| `domain`, `shop_name`, `source_url` | The shop, its name and the Google result that was checked |
| `final_label` | `shop` — independent online store selling the searched product · `uncertain` — site could not be read (WAF/403) · `non_shop` — media, marketplace, blog, price comparator, corporate site, affiliate page or off-topic store |
| `best_email` + `email_status` | Business mailbox found **on the site itself**, ranked sales@ > orders@ > info@ > contact@, MX-checked. A suggested `info@` is labelled `guessed`, never presented as found. |
| `site_type`, `platform`, `category` | online_shop / b2b_supplier / marketplace / …; Shopify, WooCommerce, Magento, PrestaShop, OpenCart, custom; product vertical |
| `phones`, `emails_all` | Other phone numbers and emails found on the shop's pages |
| `product_match` | yes / related / no — does the site sell the searched product itself |
| `registered_at`, `domain_age_years` | Domain registration date from RDAP/whois |
| `keyword`, `country`, `n_keywords`, `keywords` | Which of your keywords and markets returned this domain |
| `final_confidence`, `rationale`, `fetch_status` | Why the verdict was reached |

Plus **`report.xlsx`** in the key-value store — three sheets (`shops`, `uncertain`, `rejected`), rows coloured green / yellow / red — and `summary.json` with counts per keyword.

The dataset exports as **JSON, JSONL, CSV, XLSX, XML, HTML or RSS** (`…/items?format=csv&view=shops`) and plugs into Google Sheets, Zapier, Make, webhooks and the Apify MCP server without extra steps.

### How to find online stores that sell a product

1. Open the Actor and enter **Product keywords** — one per line, in the market's language. Specific beats generic: `cork yoga block` finds shops, `yoga` finds magazines.
2. Enter **Markets** as `country/language`: `us/en`, `gb/en`, `de/de`, `fr/fr`, `es/es`, `it/it`, `nl/nl`, `pl/pl`, `br/pt`, `mx/es` …
3. Leave **SERP pages per query** at 5 (50 Google results) for a first look; use 10 pages for exhaustive lists.
4. Click **Start**. A 3-keyword × 1-market run with 5 pages takes about 3–5 minutes and returns 30–60 shops.
5. Download the shop list (CSV, Excel, JSON) or `report.xlsx` from the **Output** tab, or pull it via API, Zapier, Make or Google Sheets.

#### Input example

```json
{
  "keywords": ["cork yoga mat", "cork yoga block"],
  "markets": ["de/de", "gb/en"],
  "maxPages": 5,
  "includeWhois": true,
  "includeContacts": true
}
```

#### Output example

```json
{
  "domain": "espressoparts.com",
  "final_label": "shop",
  "final_confidence": 0.97,
  "site_type": "online_shop",
  "platform": "shopify",
  "product_match": "yes",
  "best_email": "info@espressoparts.com",
  "email_status": "valid",
  "registered_at": "1997-08-06",
  "domain_age_years": 29.2,
  "keyword": "gooseneck kettle",
  "country": "us",
  "source_url": "https://www.espressoparts.com/collections/accessories-kettles",
  "rationale": "strong-llm shop + html agrees relevance=yes"
}
```

### How much does it cost to find online shops?

You pay **per verified shop** (`final_label = shop`): **$0.01 per shop, so 100 shops cost about $1**, plus a start fee of $0.005 per GB of memory ($0.01 at the default 2 GB). The **Pricing** tab always shows the current prices.

- **Uncertain** rows (sites behind a WAF) and **rejected** rows (marketplaces, media, off-topic stores) are pushed to the dataset **free of charge**.
- If the classifier is unavailable, the run fails before writing anything — you are never charged for unverified data.
- Set a **Maximum cost per run** and the Actor plans the search to fit it up front (fewer pages first, then fewer keywords/markets) instead of stopping half-way; the status message tells you what was trimmed.
- Results from your previous runs are cached in your account (Google results 14 days, verdicts and contacts 30 days), so repeated or overlapping keywords run faster.

The number of shops depends on keywords × markets × `maxPages`. In consumer niches one keyword × one market at 5 pages typically yields 20–30 shops.

#### Is it free to try?

Yes. On the Apify **free plan** you can run **1 keyword × 1 market × 2 Google pages** per run (about 10 domains, typically 3–8 shops with email). Extra keywords, markets and pages are dropped and the run's status message says so. Paid Apify plans have no such cap — only the run's *Maximum cost* applies.

### Options

| Input | Default | Notes |
|---|---|---|
| `maxPages` | 5 | Google pages per keyword × market (10 results each). Result counts drop sharply after page 5 for most products. |
| `includeWhois` | on | Registration date + age. Adds ~1 s per domain. |
| `includeContacts` | on | Crawl contact pages and MX-check emails. |
| `includeRejected` | off | Also push `non_shop` rows to the dataset (they are always in `report.xlsx`). |
| `maxDomains` | 300 | Safety cap on domains classified per run. |
| `useCache` / `refreshCache` | on / off | Reuse or ignore data from your previous runs. |

### How it works

1. **Search.** Each keyword × market pair is searched on Google (country + language), up to 10 pages of organic results.
2. **Filter.** Known marketplaces, platforms, media and social sites (Amazon, eBay, Etsy, AliExpress, IndiaMART, YouTube, Reddit …) are dropped before fetching.
3. **Fetch.** Every remaining landing page is downloaded with a tiered fetcher (plain HTTP → browser-grade TLS fingerprint → homepage fallback when the result URL is dead).
4. **Classify.** A Claude model reads a digest of the page and returns a structured verdict: is this site a shop, what type, does it sell *this* product, who is the real merchant behind an affiliate or doorway page. The prompt and decision rules are calibrated on a **749-domain hand-labelled set: precision 0.93, recall 0.92**.
5. **Contacts.** For shops and uncertain sites, up to 5 contact/imprint/about pages are crawled for emails and phones; every address is MX-validated.
6. **Whois.** RDAP → whois fallback chain for the registration date.
7. **Output.** Dataset items, `report.xlsx`, `summary.json`.

#### What is *not* a shop

The classifier is deliberately strict, because a lead list full of Amazon listings and blog posts is worthless:

- marketplaces and platforms (Amazon, eBay, Etsy, AliExpress, Ozon, Wildberries, IndiaMART, TradeIndia …) — even when they sell the product;
- price comparators and affiliate landing pages (the real merchant goes to `redirect_to`);
- media, blogs, forums, encyclopaedias, government pages;
- corporate/brand sites without a storefront;
- **real shops that do not sell the searched product** (a goggles store that ranked for "yoga mat" is `non_shop`, `product_match=no`).

B2B manufacturers and wholesalers that sell the product on their own domain **are** shops (`site_type=b2b_supplier`) — they are often exactly who you are looking for.

### Keyword Shop Finder vs. store-leads databases

| | Keyword Shop Finder | Store-leads databases (Store Leads, StoreCensus, BuiltWith) | Shopify-only store finders |
|---|---|---|---|
| Search by | product keyword, as typed into Google | platform, category, installed apps | keyword within Shopify stores |
| Freshness | live Google search on every run | periodic index | varies |
| Platforms | any (Shopify, WooCommerce, Magento, PrestaShop, custom …) | the ones they index | Shopify only |
| Countries and languages | any Google country / language pair | filter by store country | varies |
| Checks that the shop sells *your* product | yes (`product_match`) | no | varies |
| Email source | the shop's own pages, MX-checked | database | varies |

Use Keyword Shop Finder when you need "who sells X in Germany right now". Use a database when you need "all Shopify stores in the Home category".

### Limitations

- Sites behind a hard Cloudflare / WAF challenge cannot be read and land in `uncertain` (typically big retail chains — Fnac, Darty, Leroy Merlin, Kroger). They are listed with `fetch_status` so you can check them by hand.
- The verdict is about the **site**, not the exact page: a shop whose landing page is a blog post is still a shop.
- Large retail chains and brand-owned stores (Decathlon, Carrefour, Le Creuset …) are real shops and are labelled as such; use `domain_age_years`, `platform` and `site_type` to filter them out if you only want independents.
- Emails come only from the site's own HTML. Sites that publish no email get `email_status` empty or a clearly labelled `guessed` info@ address.
- Google results differ by day and by data centre; two runs of the same keyword may differ by a few domains.

### FAQ

#### How do I find online stores that sell a specific product?

Enter the product as you would type it into Google — `cork yoga block`, `gooseneck kettle`, `arnés para perro` — and the market (`gb/en`, `es/es`). The Actor reads Google's organic results for that exact query, opens every site and keeps only independent online shops that actually sell the product. Marketplace listings, reviews, blogs and price comparators are dropped.

#### How do I find retailers or stockists for my product?

Search for products **similar to yours** or the category you sell into: a maker of linen aprons searches `linen apron`, `linen tea towel`, `linen kitchen textiles` in each target market. Every shop in the result already sells that category online — the warmest possible list of potential stockists, with a business email for the first contact.

#### How do I find online shops in Germany, France, Spain or another country?

Set the market to the country and its language and write the keyword in that language: `de/de` + `yogamatte kork`, `fr/fr` + `tapis de yoga en liège`, `es/es` + `esterilla de yoga de corcho`. Add several markets in one run to cover a region; results are merged by domain.

#### Is this an e-commerce leads database?

No. Databases index stores by platform and category and refresh periodically. This Actor searches **live**, by **product keyword**, in **any country and language**, on **any platform**, and checks that each shop sells your product. See the comparison table above.

#### Can I find Shopify stores selling a product?

Yes. Every shop gets a `platform` field; filter the dataset by `platform = shopify`. In our test runs 50–70% of shops were on Shopify, the rest on WooCommerce, Magento, PrestaShop, BigCommerce, Squarespace and custom builds.

#### How do I find distributors, wholesalers or B2B suppliers?

Use wholesale phrasing (`wholesale cork yoga blocks`, `bamboo cutting board manufacturer`). Manufacturers, wholesalers and exporters selling on their own domain are kept as shops with `site_type = b2b_supplier`. B2B marketplaces (Alibaba, IndiaMART, TradeIndia) are filtered out.

#### Where do the emails come from? Are they verified?

Only from the shop's own pages: the landing page plus up to 5 contact, imprint and about pages. Every address is checked for a valid mail server (MX record). If a shop publishes no email, `email_status` stays empty, or shows `guessed` for a suggested info@ address — never presented as found.

#### How many shops will I get?

It depends on the niche. One keyword × one market at 5 pages typically returns 20–30 shops in consumer niches, fewer for very specific or B2B products. Use several keyword variants and markets to build a larger list; duplicates are merged by domain.

#### Can I run it on a schedule, via API or from my own code?

Yes — [Apify schedules](https://docs.apify.com/platform/schedules), the [REST API](https://docs.apify.com/api/v2), the [Python and JavaScript clients](https://docs.apify.com/api/client/python), [integrations](https://docs.apify.com/platform/integrations) with Zapier, Make, n8n and Google Sheets, and webhooks. Google results are cached for 14 days; for a scheduled re-scan turn on *Ignore cached data* so the search is fresh.

#### Can AI agents use it?

Yes. The Actor is available through the [Apify MCP server](https://mcp.apify.com), and every output field is described in the dataset schema, so an AI assistant can find it, run it and interpret the results.

#### Is it legal to collect shop contacts?

The Actor only collects information that any visitor of the site can see: public Google results, public web pages, public whois records. You are responsible for how you use the data — in particular for complying with GDPR, CAN-SPAM, PECR and similar rules when contacting the businesses found. Business contact addresses (info@, sales@) are the intended output; do not use the Actor to harvest personal data.

### Support

Use the **Issues** tab on the Actor page. Please include the run ID and the keyword/market that misbehaved — a wrong verdict with the domain is the most useful bug report.

# Actor input Schema

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

Product-level search phrases, one per line, in the language of the market (e.g. 'yogamatte kork', 'arnés para perro').

## `markets` (type: `array`):

Google country + interface language as 'cc/ll' (ISO 3166-1 alpha-2 / ISO 639-1). Examples: us/en, de/de, fr/fr, es/es, gb/en.

## `maxPages` (type: `integer`):

Google result pages to read per (keyword, market). 10 organic results per page.

## `includeWhois` (type: `boolean`):

Adds registered_at + domain_age_years. Slower (~1 s per domain).

## `includeContacts` (type: `boolean`):

Visit up to 5 contact/imprint/about pages per shop to find a business email; MX-validate every address.

## `includeRejected` (type: `boolean`):

Push non-shop rows (media, marketplaces, blogs, off-topic shops) to the dataset too. The Excel report always has all three sheets.

## `maxDomains` (type: `integer`):

Safety cap on unique domains sent to the classifier per run. Only verified shops are billed; the run's own 'Maximum cost' limit is honoured on top of this.

## `useCache` (type: `boolean`):

Reuse Google results (14 days), shop verdicts and contacts (30 days) and whois (180 days) from your previous runs. Stored in the key-value store 'keyword-shop-finder-cache' in your account; repeated or overlapping runs are much cheaper.

## `refreshCache` (type: `boolean`):

Fetch and classify everything afresh; results still update the cache.

## Actor input object example

```json
{
  "keywords": [
    "gooseneck kettle"
  ],
  "markets": [
    "us/en"
  ],
  "maxPages": 5,
  "includeWhois": true,
  "includeContacts": true,
  "includeRejected": false,
  "maxDomains": 300,
  "useCache": true,
  "refreshCache": false
}
```

# Actor output Schema

## `shops` (type: `string`):

One item per unique domain with verdict, contact email, platform and domain age. JSON/CSV/XLSX via the dataset API.

## `report` (type: `string`):

report.xlsx with three sheets: shops, uncertain, rejected — rows coloured by verdict, all evidence columns.

## `summary` (type: `string`):

summary.json: counts per keyword, SERP calls, shops with email.

# 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": [
        "gooseneck kettle"
    ],
    "markets": [
        "us/en"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("your_data_miner/keyword-shop-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 = {
    "keywords": ["gooseneck kettle"],
    "markets": ["us/en"],
}

# Run the Actor and wait for it to finish
run = client.actor("your_data_miner/keyword-shop-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 '{
  "keywords": [
    "gooseneck kettle"
  ],
  "markets": [
    "us/en"
  ]
}' |
apify call your_data_miner/keyword-shop-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,your_data_miner/keyword-shop-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/OJlMaELv2pSCuLYct/builds/FjK9lkBP06x86uL7Q/openapi.json
