Google Maps Leads Scraper – Emails, Phones & Socials
Pricing
from $0.50 / 1,000 business returneds
Google Maps Leads Scraper – Emails, Phones & Socials
Business leads from Google Maps: every place for a search plus the emails, phone numbers and social accounts its own website publishes, one row per business. Name, rating, address, hours and Place ID included. No API key, no browser. Unofficial.
Pricing
from $0.50 / 1,000 business returneds
Rating
0.0
(0)
Developer
Simple Actor
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
15 hours ago
Last modified
Categories
Share
Business leads from Google Maps, with the contact details Maps does not show. Type what you would type into Maps — "dentists in miami fl", "plumbers in london", "wedding photographers in lisbon" — and every business Google lists comes back as one row: name, category, rating, review count, address, phone and website from Maps, plus the email addresses, phone numbers and social accounts its own website publishes, and the contact form if it has one.
One run replaces the usual two-step job of scraping Maps and then crawling every website in the list.
No API key, no login, no browser, no account of yours involved.
$0.50 per 1,000 businesses, plus $1.50 per 1,000 for each business whose website gave contacts — so a lead with contacts costs $0.002, and a typical 20-business search about $0.04. Apify platform usage included, nothing else to pay. Never charged: a search that could not be read, a business your searches already delivered, and a website that publishes nothing, could not be read or was not reached.
Unofficial. Not affiliated with, endorsed by, or sponsored by Google.
Features
- Emails from the business's own website — the home page and the pages likeliest to carry them (contact, imprint, about, team), best address first: one on the business's own domain, found on a contact page.
- Phone numbers in international format — the Maps number and the ones the
website publishes, as
+13055550100, read under the business's own country so a London "020 …" comes back+44. - Social accounts as their own columns — Facebook, Instagram, LinkedIn,
X, YouTube, TikTok and WhatsApp, ready for a CSV; every other platform found
is in
social. - A status on every row —
contactsStatussays whether contacts were found, the site publishes none, there is no website, or the site could not be read and why. Filter on it. - Each business once — a business that two of your searches both find is delivered once, and a chain whose branches share one website has it read once.
- Everything Google lists — paged automatically to the end of Google's results, typically 120–140 businesses a search.
- Google's Place ID on every row, plus coordinates, opening hours, categories and a Maps link.
- Careful about wrong answers. Phone numbers and emails are read from what
the page shows and its
mailto:/tel:links, never from the page's code — where dates, prices and image ids look like phone numbers. An address left on the page by the site's website builder or one of its plugins is not reported as the business's. A Facebook or Instagram page given as a business's "website" is returned as that account, not read as a site. - Runs stay green. A search that cannot be read becomes an error row, and a website that cannot be read is a status on its business's row.
Input
{"queries": ["dentists in miami fl", "dentists in fort lauderdale fl"],"maxPlaces": 20,"maxPagesPerSite": 4,"skipPlacesWithoutWebsite": false,"language": "en","country": "US"}
| Field | Type | Default | What it does |
|---|---|---|---|
queries | array | — | Maps searches, one per line, with the place in them (plumbers in denver co). Links copied from Maps work too. |
maxPlaces | integer | 20 | Businesses per search, up to 200. Google runs out at ~120–140. |
maxPagesPerSite | integer | 4 | Website pages read per business, 1–10. 1 reads the home page only and finds about half as many emails. |
skipPlacesWithoutWebsite | boolean | false | Leave out, and do not charge for, businesses whose listing has no website. |
reviewCounts | boolean | true | Re-read a Maps page Google answered without review counts. |
language | string | en | What Google answers in: en, de, fr, es, ja, pt-BR… |
country | string | US | Two-letter code: the country Google reads the search from. Set it to the place's country — it decides which city a shared name means. |
Put the place in the search. Google answers "plumbers" alone for wherever it thinks the request came from, which is a data centre, not you. To get more businesses in one area, split the search by neighbourhood or by a narrower category.
Name the country when a city's name exists in more than one. Google
reads "dentists in manchester" through country, which defaults to US, so it
can come back as Manchester, New Hampshire, as Manchester, England, or as a
mix of the two that changes from one page of results to the next. Measured
with the default: 8 of 20 pages were all New Hampshire and 10 mixed both;
with country set to GB, all 20 were England. Birmingham (Alabama) and
London (Ontario, Ohio) mixed in the same way. Write "dentists in manchester
uk", or set country to the place's country. Every row's countryCode says
where that business is.
Output
One item per business, in the run's dataset:
{"type": "place","position": 6,"name": "ONE Dental Miami","placeId": "ChIJOeo2vFu22YgRnXmUhbsc1LE","address": "1330 Coral Wy #100, Miami, FL 33145","countryCode": "US","phone": "(305) 285-5150","phoneE164": "+13052855150","website": "http://www.onedentalmiami.com/","rating": 4.8,"reviewCount": 371,"category": "Dentist","contactsStatus": "found","email": "info@onedentalmiami.com","emails": ["info@onedentalmiami.com"],"websitePhones": ["+13052855150","+13052855174"],"facebook": "https://www.facebook.com/onedentalm","instagram": "https://www.instagram.com/onedentalmiami","linkedin": null,"twitter": null,"youtube": "https://www.youtube.com/@ONEDentalMiami","tiktok": null,"whatsapp": null,"social": {"facebook": "https://www.facebook.com/onedentalm","youtube": "https://www.youtube.com/@ONEDentalMiami","instagram": "https://www.instagram.com/onedentalmiami"},"messaging": {},"contactFormUrl": "https://www.onedentalmiami.com/contact-our-dental-office/","domain": "onedentalmiami.com","websitePagesRead": 4,"contactsError": null,"query": "dentists in miami fl","retrievedAt": "2026-10-18T16:54:36.634Z"}
Every row also carries cid, categories, latitude, longitude,
openingHours, imageUrl, googleMapsUrl, searchUrl and page.
contactsStatus | What it means |
|---|---|
found | The website gave at least one email, phone number or social account. |
none_found | The website was read and publishes none of them — often true of small businesses. |
no_website | The Maps listing has no website. The Maps phone and address are still there. |
social_profile | The listing's "website" is a social account; it is filled into that column, and nothing is read. |
unreadable | The website could not be read — down, refusing automated readers, or too slow. contactsError says which. |
not_read | The run reached its own time limit before this website. |
A search that could not be read is its own row with type: "error", an
error code (bad_input, read_failed, timed_out or parse_failed) and an
errorDescription. The run stays green either way and its status message
counts them, so if you run on a schedule, check for type: "error" rows
rather than the run status.
An empty dataset means every search was read and Google Maps lists no businesses for it.
Runs that reach their time limit
A run stops shortly before its own timeout and keeps everything it has
delivered — rows go out as their websites are read, not at the end. A search
it never reached gets a timed_out row, and a business whose website it had
no time for arrives with contactsStatus: "not_read". A 20-business search
takes about a minute; raise the timeout or split the run for long lists.
When a run does fail, this Actor reports the failure to its author so it can be fixed: the error and where in the code it happened, how long the run had been going and what it had delivered, and the shape of the input — how many searches, how deep, which language and country. Your search terms and your results are never part of that report.
How to use
From Apify Console
- Put one search per line into Searches, with the place in it.
- Set Businesses per search — Google has 120–140 for most searches.
- Click Start, then open the Dataset tab: the Leads view is one line per business with its email, phone and accounts; export as CSV or Excel.
From the API
curl -s "https://api.apify.com/v2/acts/simple.actor~google-maps-leads/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{"queries": ["dentists in miami fl"], "maxPlaces": 60}'
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('simple.actor/google-maps-leads').call({queries: ['dentists in miami fl', 'dentists in fort lauderdale fl'],maxPlaces: 100,});const { items } = await client.dataset(run.defaultDatasetId).listItems();const withEmail = items.filter((row) => row.email);
From Claude
Claude can run this Actor for you through Apify's MCP server. This connector URL gives it this Actor, Website Contacts, Google Ads Transparency and LinkedIn Jobs, and nothing else:
https://mcp.apify.com/?tools=simple.actor/google-maps-leads,simple.actor/website-contacts,simple.actor/google-ads-transparency,simple.actor/linkedin-jobs
On claude.ai or the desktop app, go to Customize → Connectors → + Add → Add
custom connector, paste the URL and sign in to Apify; in Claude Code, run
claude mcp add --transport http lead-tools "<url>", then /mcp to sign in.
Runs are charged to your Apify account at the prices above.
A tested prompt:
Use the Google Maps leads tool to find dentists in Miami, FL. Ask for 40 businesses so that at least 20 have an email. Wait until the run has finished before you read the results. Then give me a table of the ones with an email: name, email, phone, website, rating.
It found 40 dentists, 21 of them with an email, in 110 seconds, for $0.074. Ask for about twice the businesses you need, because about half publish an email, and tell Claude to wait: a read before the run ends returns a partial list that looks complete. The full guide has the transcript and what to check before you email anyone.
Use cases
- Cold outreach — every business of a kind in an area, with an email to write to and a number to call.
- Agency prospecting — local businesses with no website, or with no Instagram, are the ones to pitch.
- CRM enrichment — the same Place ID, phone and accounts for businesses already on your list.
- Market research — how many competitors a category has in a city, how they rate, and how they present themselves online.
FAQ
Why does a business have no email? Many small businesses publish only a
phone number and a contact form; contactsStatus tells "the site has none"
(none_found) from "the site could not be read" (unreadable).
Why is a website unreadable? Some sites refuse automated readers, some
are down, and some take longer than 40 seconds. The reason is in
contactsError.
Does it read pages behind a login, or run a browser? No. It reads what a website serves to any visitor, which is where businesses publish their contact details.
Is it legal? It reads business contact details that businesses publish publicly for the purpose of being contacted. You are responsible for how you use them, including the rules on unsolicited messages where you and your recipients are.