Google Maps Email Scraper: Verified Business Emails & Phones avatar

Google Maps Email Scraper: Verified Business Emails & Phones

Pricing

from $1.14 / 1,000 leads

Go to Apify Store
Google Maps Email Scraper: Verified Business Emails & Phones

Google Maps Email Scraper: Verified Business Emails & Phones

Get business emails from Google Maps search results. Each email's domain is checked for a live mail server, and you pay only for businesses that come back with a working email. Places with no email are free. Includes phone, website, address, rating and hours. No login. Works in AI agents via MCP.

Pricing

from $1.14 / 1,000 leads

Rating

5.0

(1)

Developer

The Mine Works

The Mine Works

Maintained by Community

Actor stats

0

Bookmarked

55

Total users

18

Monthly active users

2 days ago

Last modified

Share

60 Phoenix dentists in 130 seconds

From The Mine Works, makers of Threads Scraper and B2B Leads Finder, with nearly 139,000 runs across our actors.

Type a Google Maps search such as dentists in Phoenix AZ or plumbers in Leeds. The actor returns each business with its phone, website, address, category, rating, coordinates and Google Maps link, then visits the business website, reads the email address from it and checks that the email's domain has a working mail server. You are charged only for businesses that come back with an email that passes that check.

Why choose this actor?

  • Pay only for businesses with a working email. In our latest test, 60 Phoenix dentists came back and 14 had an email that passed the mail server check. Only those 14 would be charged; the other 46 rows were delivered free.
  • Every email is checked, and the check is stated honestly. The domain of each address is looked up for DNS mail (MX) records, and domains with none, domains that do not exist and "null MX" domains fail. Each address in all_emails carries its own result, so you can see what failed and why.
  • Never pay twice for the same business. With deduplicateAcrossRuns on (the default), a business delivered to your account in an earlier run is skipped before its website is visited. No login, cookies or Places API key, and the datacenter proxy it needs is included.

Run it on Apify

Part of The Mine Works Leads and business directories family: B2B Leads Finder, Skip Trace Lookup, JustDial Scraper, 2GIS Places Scraper, IndiaMART Scraper, Yandex Maps Scraper.

Try it in one minute

Paste this into the JSON tab of the input form and press Start:

{
"searchQueries": ["dentists"],
"location": "Boise, ID",
"maxLeadsPerQuery": 10
}

You get 10 businesses back; the ones with a working email are marked charged: true. Give searches in searchQueries, one per line, either complete (dentists in Boise ID) or as a business type with a location that is added to each one. Input copied from other Google Maps actors also works: searchStringsArray, queries or keywords for the searches, locationQuery or city for the place, and maxCrawledPlacesPerSearch for the limit.

Apify's free plan includes $5 of credit every month, which covers about 2,500 verified leads at this actor's Free plan price ($0.0019 a verified lead plus $0.005 a run, in runs of about 100 verified leads). Businesses without a working email are free, so they do not use up that credit.

Copy to your AI assistant

Paste this block into ChatGPT, Claude, Cursor or any assistant that can write code, and it can run the actor for you.

themineworks/maps-leads on Apify. Searches Google Maps, visits each business website for an email address, checks the email's domain for live mail (MX) records, and charges only for businesses with an email that passes. Call ApifyClient("TOKEN").actor("themineworks/maps-leads").call(run_input={...}), then client.dataset(run["defaultDatasetId"]).list_items().items. Required: searchQueries (array of Google Maps searches such as "dentists in Boise ID"). Optional: location (string added as " in <location>" to each search, default none), maxLeadsPerQuery (integer 1 to 200, default 5), verifyEmails (boolean, default true), deduplicateAcrossRuns (boolean, default true), includeFields (array, default all 9 business fields), language (default "en"), proxyConfig (default Apify datacenter proxy). Rows with charged true are the verified leads; rows with _type "summary" or "info" are run reports. Full spec: GET https://api.apify.com/v2/acts/themineworks~maps-leads/builds/default (Bearer TOKEN), which returns inputSchema and readme. Token: https://console.apify.com/account/integrations

Key features

  • Up to 200 places per search. Google Maps returns 20 places a page and stops paging at about 200, so that is the cap per search. Add one search per neighborhood or suburb for more.
  • 14 business fields plus 3 status fields per row. Place ID, name, category, address, phone, website, rating, hours, coordinates, Google Maps link, the search that found it, the email, its status and every address found with its own result.
  • 2 pages read per website, 8 websites at a time. The homepage first, then /contact only if the homepage had no address on the business's own domain. Up to 5 addresses per page are kept, from the visible text and from mailto: links; scripts and styles are ignored.
  • A result on every address, 3 of them billable. valid, role_based (a shared inbox such as info@ or sales@) and the rare catch_all_likely pass and are charged; invalid (no mail server) and unverifiable (the DNS lookup timed out) fail and are free, as is a malformed address (syntax_error).
  • Memory across runs, keyed on Google's place ID. Delivered places are stored by Google's place ID in a key value store named maps-leads-seen in your account, so repeat runs of the same search move on to new businesses.
  • 9 fields you can switch off. includeFields trims the row to what you need, for example just name, phone and email; the email, status and billing fields always stay.

How to use it

Basic: one trade in one city

{
"searchQueries": ["plumbers in Leeds"],
"maxLeadsPerQuery": 50
}

maxLeadsPerQuery counts every new place the search processes, with or without an email. Only the ones with a working email are charged, so a search of 50 places in a trade where one business in four publishes an email costs you about 12 or 13 leads.

Several searches at once

{
"searchQueries": ["dentists", "orthodontists", "pediatric dentists"],
"location": "Austin, TX",
"maxLeadsPerQuery": 100
}

Each line is its own search, and location is added to each as dentists in Austin, TX. A search that already names the place is left alone. A business that turns up in two searches of the same run is delivered once, and the summary row counts the repeats in duplicates_in_run.

Cover a whole city, neighborhood by neighborhood

{
"searchQueries": [
"roofers in Downtown Phoenix AZ",
"roofers in Scottsdale AZ",
"roofers in Tempe AZ",
"roofers in Mesa AZ",
"roofers in Glendale AZ"
],
"maxLeadsPerQuery": 200
}

One search stops at about 200 places, so a dense trade in a large metro needs several narrower searches. With deduplicateAcrossRuns on, you can run the list again next month and receive only businesses you have not had before.

Weekly prospect list for an agency

{
"searchQueries": ["med spas in Miami FL", "med spas in Fort Lauderdale FL"],
"maxLeadsPerQuery": 100,
"includeFields": ["name", "phone", "website", "email", "rating"]
}

Save it as a task and add a weekly schedule (Apify Console, Schedules, cron 0 8 * * 1 for Mondays at 8:00). Each run skips businesses already delivered, so the list you receive is businesses you have not been sent before, such as new listings. A business delivered earlier without an email is skipped too, so switch deduplicateAcrossRuns off once in a while to recheck those. A run with nothing new charges no leads, only the $0.005 run fee.

Emails without the check

{
"searchQueries": ["florists in Denver CO"],
"maxLeadsPerQuery": 25,
"verifyEmails": false
}

With verifyEmails off, the mail server check is skipped, every business with any extracted address is charged, and email_status is unverified. Use it only if you run your own verifier afterwards; with the check on, dead domains cost you nothing.

Input parameters

ParameterTypeDefaultWhat it does
searchQueriesarray of stringsnone (prefill coffee shops)Google Maps searches, one per line, written the way you would type them into Maps. Each line is its own search.
locationstringnone (prefill Austin, TX)A city, region or address. When set, in <location> is added to every search that does not already name it.
maxLeadsPerQueryinteger5New places to process per search, 1 to 200. Places with and without an email both count; only places with a working email are charged.
languagestringenGoogle Maps interface language, for example de. Changes category names and hours labels.
verifyEmailsbooleantrueCheck each email's domain for a live mail server and charge only for businesses with a passing address. Off charges any extracted email.
includeFieldsarrayall 9: name, address, phone, website, email, rating, hours, category, coordinatesBusiness fields to keep in each row. Email, status and billing fields are always kept.
deduplicateAcrossRunsbooleantrueRemember every place delivered to your account in the maps-leads-seen key value store and skip it in later runs. Turn off, or delete that store, to get them again.
proxyConfigobjectApify proxy (datacenter)Proxy for Google Maps and the business websites. The datacenter default is enough and is included in the price.

What data do you get?

Every place the search processes becomes one row, charged or not, and each run ends with report rows.

The business (from Google Maps): place_id, name, category, address, phone, website, rating, hours, coordinates (lat, lng), google_maps_url, query_used.

The email (from the business website): email (the best address that passed), email_status, and all_emails, a list of every address found, each with email, status, mx_found and confidence.

Billing and status: charged (true for a verified lead), enrichment_status (email_verified when an address passed, full when the check is off and an address was found, no_email or no_website for free rows) and scraped_at.

Report rows (never charged): a _type: "summary" row with queries_run, places_found, verified_email_leads, places_charged, places_no_email, skipped_already_delivered, duplicates_in_run, total_emails_verified and whether a guard stopped the run (profit_guard_tripped, yield_guard_tripped); and, when at least one lead was charged, a _type: "info" row with a short message.

A few things to know about the fields:

  • hours is short. In every row of our recent runs it held one day only, the day of the run, for example {"Tuesday": ...}, not the full week.
  • rating is the star rating. The review count and open or closed status are not in the Google Maps feed this actor reads, so they are not returned; a permanently closed business with a live email can be charged.
  • email prefers an address on the business's own domain. A Gmail or Yahoo address the business publishes counts too: in our Phoenix test, 3 of the 6 valid addresses were Gmail.
  • Fields with no value are left out of the row rather than sent as null, so a place with no website on Google Maps has no website key.

Stable fields for automations

These fields were present in every place row of our latest test runs (63 rows across two runs, default includeFields), and their names will not change.

FieldWhat it holds
place_idGoogle's identifier for the place, also the key for skipping it later
nameBusiness name as shown on Google Maps
categoryMain Google Maps category, for example Dentist
addressStreet address, without the business name
coordinates{ "lat": ..., "lng": ... }
google_maps_urlA https://www.google.com/maps?cid=... link to the place
query_usedThe exact search that returned this place, with the location added
all_emailsEvery address found with its check result; an empty list when none
chargedtrue if this row is a billed verified lead
enrichment_statusemail_verified, full, no_email or no_website
scraped_atISO 8601 timestamp

phone, website, rating, hours, email and email_status appear whenever there is a value. We may add fields, but we will not rename these.

Output examples

Real rows from our local test run of the live build, searchQueries: ["dentists in Phoenix AZ"], 60 places. hours is trimmed from each.

A charged lead with an address on the business's own domain:

{
"place_id": "0x872b1254fe4866ef:0xbfc5fe74d6093112",
"name": "Encanto Family Dental Care",
"category": "Dentist",
"address": "1525 W Thomas Rd, Phoenix, AZ 85015",
"phone": "(602) 666-9961",
"website": "https://www.encantofamilyaz.com/",
"rating": 4.8,
"coordinates": { "lat": 33.480266199999996, "lng": -112.09258 },
"google_maps_url": "https://www.google.com/maps?cid=13818730809416823058",
"query_used": "dentists in Phoenix AZ",
"email": "responses@encantofamilyaz.com",
"email_status": "valid",
"all_emails": [
{ "email": "responses@encantofamilyaz.com", "status": "valid", "mx_found": true, "confidence": 1 }
],
"charged": true,
"enrichment_status": "email_verified",
"scraped_at": "2026-09-29T22:57:31.910Z"
}

A charged lead whose only address is a shared inbox. role_based addresses pass the check and are charged:

{
"place_id": "0x872b730c1d9137c9:0xf991306ef37ef501",
"name": "Life Smiles Dental Care",
"category": "Dentist",
"address": "4611 E Shea Blvd Ste 250, Phoenix, AZ 85028",
"phone": "(602) 786-5484",
"website": "https://www.lifesmilesdentalcare.com/",
"rating": 5,
"email": "info@lifesmilesdentalcare.com",
"email_status": "role_based",
"all_emails": [
{ "email": "info@lifesmilesdentalcare.com", "status": "role_based", "mx_found": true, "confidence": 0.75 }
],
"charged": true,
"enrichment_status": "email_verified"
}

A free row: the website shows an address, but its domain has no mail server (it looks like a typo on the site), so it fails and nothing is charged:

{
"place_id": "0x872b6acddb1bc657:0x44c5d1d9db5c668f",
"name": "Westwind Dental Phoenix",
"category": "Dentist",
"phone": "(480) 470-8781",
"website": "https://www.westwindintegratedhealth.com/?utm_source=phoenix-listing&utm_medium=gmb&utm_campaign=seo&utm_content=website-link",
"rating": 4.2,
"all_emails": [
{ "email": "appointments@westiwndih.com", "status": "invalid", "mx_found": false, "confidence": 0 }
],
"charged": false,
"enrichment_status": "no_email"
}

A free row: the website shows no address at all:

{
"place_id": "0x872b12b37bded0c5:0x548c758696f5db3",
"name": "Central Valley Dentistry & Implants",
"category": "Dentist",
"address": "6232 N 7th St Unit 201, Phoenix, AZ 85014",
"phone": "(602) 246-0385",
"website": "https://www.centralvalleydentistry.com/?utm_campaign=gmb&utm_medium=organic&utm_source=gmb",
"rating": 4.9,
"all_emails": [],
"charged": false,
"enrichment_status": "no_email"
}

The summary row from Apify run TilcKyClhXTijwqy6 (3 Boise dentists, 1 charged), trimmed:

{
"_type": "summary",
"queries_run": 1,
"places_found": 3,
"verified_email_leads": 1,
"places_charged": 1,
"places_no_email": 2,
"skipped_already_delivered": 0,
"duplicates_in_run": 0,
"total_emails_verified": 1,
"dedupe_across_runs": false,
"profit_guard_tripped": false,
"yield_guard_tripped": false
}

Pricing

Pay per event. You pay for each verified lead written to your dataset, at the rate for your Apify plan, plus a small fee per run. Proxy and compute are included.

EventFreeBronze (Starter)Silver (Scale)Gold and above (Business)
lead-verified, per verified lead$0.0019$0.0016$0.00135$0.00114
per 1,000 verified leads$1.90$1.60$1.35$1.14
apify-actor-start, per run$0.005$0.005$0.005$0.005

These prices have applied since 14 September 2026, when the run fee was added; the per lead price has not changed since 27 July 2026. From 14 October 2026 (12:00 UTC) the price per verified lead rises to $0.009 on Free, $0.0075 on Bronze, $0.0062 on Silver and $0.005 on Gold and above, which is $9.00, $7.50, $6.20 and $5.00 per 1,000. The run fee stays $0.005. The Pricing tab shows this change with its start date. A price increase has to be announced at least 14 days ahead, and it then shows on the Pricing tab with its start date. The Pricing tab always shows the rate for your own plan.

The run fee is Apify's standard start event: one event per GB of run memory, with a minimum of one. At the default 512 MB, and at anything up to 1 GB, that is one event, $0.005 a run. At 2 GB it would be $0.01. The actor does not need more than the default.

What a real job costs. 100 verified leads in one run cost $0.195 on the Free plan ($0.19 plus the $0.005 run fee) and $0.119 on Gold. 1,000 verified leads in ten runs cost $1.95 on Free and $1.19 on Gold. How many places you search to get there depends on the trade: in our tests 14 of 60 Phoenix dentists, 9 of 20 Portland bakeries and 5 of 25 Denver florists had a working email, and you pay nothing for the rest.

Never charged:

  • places with no website, no email on the website, or only emails that fail the check (no_website, no_email)
  • businesses skipped because they were delivered to your account in an earlier run
  • a business returned twice by searches in the same run
  • a row that fails to save; the charge is made only after the row is in your dataset
  • the _type: "summary" and _type: "info" report rows

A run that finds no verified lead charges no lead events, only the $0.005 run fee.

FAQ

What does this actor search? Google Maps, through the same results feed the Maps web page uses, read over plain HTTP. Then each business's own website, for the email. It does not use the Google Places API, so you need no API key.

How many businesses can I get? Up to 200 new places per search, set with maxLeadsPerQuery (default 5, so raise it). A narrow search often has fewer. For a large city, add one search per neighborhood or suburb; there is no limit on the number of searches in a run. The default run timeout is 10 minutes; at the pace of our tests (60 places in 94 to 130 seconds) that fits a few hundred places, so split bigger jobs across runs or raise the timeout. A run that reaches its timeout keeps everything delivered and ends with its summary row.

How fresh is the data? Everything is read live during your run: the Google Maps listing as it is today and the business website as it is today. Nothing comes from a stored database.

Are the emails verified? The domain is. Each address is checked for correct syntax, then its domain is looked up for DNS mail (MX) records. No mail server, a domain that does not exist, a "null MX" record that says the domain takes no mail, or a lookup that times out after 3 seconds all fail. The actor does not open an SMTP connection to test the mailbox itself, because that needs outbound port 25, which Apify and other cloud platforms block. So an address on a live domain can still bounce if that one mailbox was closed. Filter on email_status for valid only if you want to leave out shared inboxes.

Why do so many businesses come back without an email? Many small businesses list only a phone number, hide their address behind a contact form, or show it in an image or a script. The actor reads the visible text and mailto: links of the homepage and, when needed, /contact. If neither shows an address, the row comes back free as no_email. Businesses with no website on Google Maps come back free as no_website.

Will I be charged twice for the same business? No, while deduplicateAcrossRuns is on (the default). Delivered places are remembered in the maps-leads-seen key value store in your Apify account and skipped in later runs; the summary row counts them in skipped_already_delivered. If that store cannot be opened, the run says so in the log and delivers everything. Delete the store in Apify Storage to start fresh.

Do I need a Google account, cookies or a proxy? No account, no cookies, no API key. The default Apify datacenter proxy is enough for this feed and for business websites, and it is included in the price.

What if Google blocks a request? A rate limited page is retried, and the actor moves on to the next search after repeated refusals. Three blocked requests in a row stop the run, the summary row shows yield_guard_tripped, and nothing is charged for places never processed. The run also stops itself if it costs far more than it earns, for example when almost no business in a trade publishes an email; everything delivered so far stays in your dataset.

What formats can I export? JSON, CSV, Excel, XML, RSS or an HTML table from the dataset tab, or through the Apify API.

Can I run it on a schedule? Yes. Save your input as a task, then add a schedule in Apify Console. Keep deduplicateAcrossRuns on so each run returns only businesses you have not received.

Can I use it from Claude, ChatGPT or another AI agent?

  • Connector URL: https://mcp.apify.com/?tools=themineworks/maps-leads.
  • Claude: Settings > Connectors > Add custom connector, paste the URL, sign in with Apify.
  • ChatGPT: developer mode, add an MCP connector with the URL, sign in with Apify.
  • Cursor or VS Code: add it as an HTTP MCP server with that URL.
  • Claude Code: claude mcp add -t http maps-leads "https://mcp.apify.com/?tools=themineworks/maps-leads".

Is it legal? The actor reads public Google Maps results and public business websites, the same pages anyone can open without an account, and the mail check reads public DNS records without contacting the mailbox. A business email can still be personal data when it names a person, for example a sole trader's own address. You are responsible for how you use the data, including Google's and the websites' terms, data protection law such as GDPR and CCPA, and anti-spam rules such as CAN-SPAM for outreach. This is general information, not legal advice.

Integrations

  • Google Sheets: send each run's verified leads to a sheet with Apify's Google Sheets integration.
  • Make, Zapier and n8n: start a run, keep rows where charged is true, and push them to your CRM or email tool.
  • Webhooks: have Apify call your URL when a run finishes.
  • API: start runs and read datasets from any language with the Apify API or the Python and JavaScript clients.
  • MCP clients: Claude, ChatGPT, Cursor and other MCP clients can call the actor as a tool through https://mcp.apify.com.

More from The Mine Works

Leads and business directories

Social media and video

Marketing, SEO and reviews

LinkedIn

Real estate

Science, health and government data

Jobs and hiring

E-commerce and marketplaces

Company and business data

Food and local services

Developer and AI tools

More tools

Support

Found a bug or a search that returns nothing when it should? Open an issue in the Issues tab on this page. To ask for a new data source, email dmineworks@gmail.com.

Google and Google Maps are trademarks of Google LLC. This actor is not affiliated with or endorsed by Google.

Google Maps Email Scraper turns a Maps search into a list of local businesses with emails checked against live mail servers, and charges only for the ones that pass.