Scrape Google Maps business listings and enrich them with verified emails. Searches by keyword and location, extracts business name, address, phone, website, hours, ratings, and reviews count, then optionally crawls each website to find and MX-verify email addresses. You only pay for leads with a verified email.
Run it on Apify: apify.com/themineworks/maps-leads Docs, FAQ and pricing: themineworks.com/actors/maps-leads
Price: From $1.14 per 1,000 verified leads on Apify's higher plans ($1.90 on the free plan), plus a $0.005 start fee per run. Failed and empty results are never charged.
- Search Google Maps by keyword and location
- Business name, address, phone, website, ratings, review count
- Optional email extraction from business websites
- MX-record email verification. Only pay for valid emails
- Deduplication across runs via persistent key-value store
- Supports multiple search queries in one run
You need a free Apify account and its API token (Settings, API & Integrations).
pip install apify-clientfrom apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("themineworks/maps-leads").call(run_input={
"searchQueries": [
"coffee shops"
],
"location": "Austin, TX"
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item)npm install apify-clientimport { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('themineworks/maps-leads').call({
"searchQueries": [
"coffee shops"
],
"location": "Austin, TX"
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);One request that runs the actor and returns the results in the response (for runs under 5 minutes):
curl -X POST "https://api.apify.com/v2/acts/themineworks~maps-leads/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"searchQueries": ["coffee shops"], "location": "Austin, TX"}'This repo includes ready-made clients that save results to JSON and CSV:
python3 google_maps_email_scraper.py --token YOUR_APIFY_TOKEN --search-queries "coffee shops" --location "Austin, TX"
node google_maps_email_scraper.mjs --token YOUR_APIFY_TOKEN --search-queries "coffee shops" --location "Austin, TX"| Field | Type | Default | Description |
|---|---|---|---|
searchQueries |
array | What to search on Google Maps, one search per line, written the way you would type it into Maps | |
location |
string | Optional | |
maxLeadsPerQuery |
integer | 5 |
Most new places to process for each search, from 1 to 200 |
language |
string | "en" |
Google Maps interface language code, for example "en" for English or "de" for German |
verifyEmails |
boolean | true |
On (recommended): every email found is checked for a live mail server on its domain, and only businesses with… |
includeFields |
array | ["name", "address", "phone", " |
Which business fields to keep in each row, for example just name, phone and email |
deduplicateAcrossRuns |
boolean | true |
On: remembers every place this actor has delivered to your account (in a key-value store named… |
One row per result, as JSON, CSV, Excel or through the API.
| Field | Type | Description |
|---|---|---|
place_id |
string | Google Maps place identifier (hex feature ID such as 0x...:0x...), used for deduplication across runs |
name |
string | Business name |
category |
string | Business category |
address |
string | Full address |
phone |
string | Phone number |
website |
string | Business website URL |
email |
string | Best verified email address found |
email_status |
string | Status of the best email: valid, role_based, catch_all_likely, or unverified when verification is off |
all_emails |
array | All emails found with their verification status |
rating |
number | Google Maps star rating |
hours |
object | Opening hours by day, when Google publishes them |
coordinates |
object | Latitude and longitude coordinates |
query_used |
string | Search query that returned this business |
charged |
boolean | Whether this row is a chargeable lead (a working email was found) |
enrichment_status |
string | Outcome: email_verified (charged), full (charged, verification off), no_email or no_website (both free) |
scraped_at |
string | ISO-8601 timestamp when this record was scraped |
google_maps_url |
string | Google Maps link for the place |
The actor works as a tool in Claude, Cursor or any MCP client through Apify's MCP server:
https://mcp.apify.com/?tools=themineworks/maps-leads
The actor checks that the domain has valid MX records (meaning it can receive email). Only leads passing this check are charged. Failed lookups and businesses without emails are always free.
Yes. The searchQueries input accepts a list of keyword + location pairs, all processed in a single run.
From $1.14 per 1,000 verified leads on Apify's higher plans ($1.90 on the free plan), plus a $0.005 start fee per run. Failed and empty results are never charged. You can cap what a single run may spend with the maximum cost setting on Apify.
Yes. Every run saves to an Apify dataset you can download as JSON, CSV, Excel or XML, or read through the API. The Python and Node clients in this repo also write the results to local files.
Yes. Save your input as a task on Apify and attach a schedule, or call the API from your own cron job. Scheduled runs are billed the same way as manual ones.
- B2B Leads Finder: Business emails and LinkedIn profiles for target companies
- LinkedIn Company Scraper: Company size, industry, website, and followers without login
- Zillow Rental Listings Scraper: Scrape Zillow for-rent listings by city or zip. $1 per 1,000 results
Part of The Mine Works: 151 pay-per-result scrapers with no login and no browser setup on your side.
MIT © The Mine Works