Google Maps Leads Scraper – Emails, Phones & Socials avatar

Google Maps Leads Scraper – Emails, Phones & Socials

Pricing

from $0.50 / 1,000 business returneds

Go to Apify Store
Google Maps Leads Scraper – Emails, Phones & Socials

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

Simple Actor

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

15 hours ago

Last modified

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 — contactsStatus says 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"
}
FieldTypeDefaultWhat it does
queriesarray—Maps searches, one per line, with the place in them (plumbers in denver co). Links copied from Maps work too.
maxPlacesinteger20Businesses per search, up to 200. Google runs out at ~120–140.
maxPagesPerSiteinteger4Website pages read per business, 1–10. 1 reads the home page only and finds about half as many emails.
skipPlacesWithoutWebsitebooleanfalseLeave out, and do not charge for, businesses whose listing has no website.
reviewCountsbooleantrueRe-read a Maps page Google answered without review counts.
languagestringenWhat Google answers in: en, de, fr, es, ja, pt-BR…
countrystringUSTwo-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.

contactsStatusWhat it means
foundThe website gave at least one email, phone number or social account.
none_foundThe website was read and publishes none of them — often true of small businesses.
no_websiteThe Maps listing has no website. The Maps phone and address are still there.
social_profileThe listing's "website" is a social account; it is filled into that column, and nothing is read.
unreadableThe website could not be read — down, refusing automated readers, or too slow. contactsError says which.
not_readThe 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

  1. Put one search per line into Searches, with the place in it.
  2. Set Businesses per search — Google has 120–140 for most searches.
  3. 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.