Google Maps Leads Extractor & Scraper β€” Emails | $2.49/1k avatar

Google Maps Leads Extractor & Scraper β€” Emails | $2.49/1k

Pricing

$2.49 / 1,000 business leads

Go to Apify Store
Google Maps Leads Extractor & Scraper β€” Emails | $2.49/1k

Google Maps Leads Extractor & Scraper β€” Emails | $2.49/1k

Turn Google Maps searches into CRM-ready local business leads: emails, websites, socials, booking links, unclaimed-profile detection, 0-100 lead scores, dedup & new-lead tracking.

Pricing

$2.49 / 1,000 business leads

Rating

0.0

(0)

Developer

Raffy

Raffy

Maintained by Community

Actor stats

0

Bookmarked

5

Total users

1

Monthly active users

19 days ago

Last modified

Categories

Share

Google Maps Local Leads Enricher β€” Emails, Websites & Lead Scores πŸ—ΊοΈπŸ“§

Turn any Google Maps search into a CRM-ready list of local business leads β€” complete with emails, websites, phone numbers, social profiles, booking-system detection, unclaimed Google Business Profile detection, a 0–100 lead score, automatic deduplication, and cross-run new-lead tracking.

This is a lead generation tool, not a generic scraper. Every row answers three questions: Who can I contact? What can I sell them? Why now?

πŸ“ˆ Benchmark (real runs, v1.8.0, 2026-09-27)

Four real queries β€” dentists in Austin, HVAC contractors in Phoenix, law firms in Miami, plumbers in Denver β€” 20 leads each, proxy-free, default settings (detail mode), 80 leads:

MetricResult (detail mode, the default)
Records shipped80
% with phone β€” all valid E.164100%
% with website100%
% reachable (phone/email/website)100% (hard gate; 0 place-only rows shipped)
address / street / city / state / postal / country fill99% / 99% / 99% / 99% / 99% / 99% ΒΉ
lat-lng / place_id / CID / plus code fill100% / 100% / 100% / 99%
rating / review count / open-now / opening-hours fill100% / 100% / 98% / 93%
claimed-by-owner / attributes / tech-stack fill100% / 80% / 90%
% with email44%
% with social profile83%
% with decision-maker hint64%
contact page / resolved website URL / booking links76% / 94% / 53%
sub-scores, reachableChannels, opportunitySignals, fieldSources100% of records
Addresses containing button labels or phone numbers0
Duplicates shipped (by place_id)0
Avg lead score84.4 (0 low / 8 medium / 37 high / 35 very-high)
Speed48–61 s per 20 leads on a desktop (β‰ˆ2.5–3 s/lead, website enrichment included). On Apify (4 GB), 20-lead runs measured 83–130 s since 1.9 (4–6.5 s/lead; 141–256 s before)

ΒΉ The missing 1% is a service-area plumber that publishes no street address. It ships address: null and serviceAreaBusiness: true, never button text.

Same four queries in ⚑ lite mode (skipPlaceDetailPages: true): 60 leads at 7–23 s per query (100% website, 100% E.164 phones, street address on 98%, 0 dupes, 0 unreachable shipped). The data is thinner: city / state / postalCode / country are empty unless you pass locations; there is no plus code, hours, attributes or claim status; and review counts appear only when the card shows them (18% of rows in this run). Dentists in Austin shipped 0 of 20 in lite mode: their result cards showed neither a phone nor a website, so every place failed the reachability gate. Use the default detail mode for searches like that. Lite trades depth for speed; detail trades speed for depth. Both ship only reachable, deduplicated leads.

Honest notes: priceLevel is empty for these verticals (Maps shows it mainly for restaurants/retail). A global maxResults is shared across queries, so a later query can be starved if the first ones fill the quota β€” raise maxResults or run one query per task for even coverage. Data Google hides from headless browsers (rating distribution, review velocity, popular times, photo count) is not included rather than faked. Speed depends on the machine and on how fast each business website answers.

✨ What you get for every business

πŸ“‡ Contact dataπŸ”Ž Opportunity intelligenceπŸ“Š Google Maps data
Email(s) (incl. obfuscated & Cloudflare-protected)0–100 lead score + quality labelName, primary + secondary categories
Phone in E.164 (Maps and website)Reachability / reputation / completeness sub-scoresFull address β†’ street / city / state / postal / country
Website + resolved final URL + domain⭐ Unclaimed Google Business Profile flagRating & review count
Decision-maker hint (name + title from About/Team)Tech stack (CMS + analytics/ads/commerce)Attributes (wheelchair, LGBTQ+, women-owned, …)
Contact-page deep linkWebsite platform (WordPress, Wix, Squarespace, …)Open-now, opening hours, price level, plus code
Facebook, Instagram, LinkedIn, YouTube, TikTok, X, Pinterest, WhatsAppBooking-link detection (Calendly, Fresha, OpenTable, Zocdoc + 30 more)Latitude / longitude, place_id, CID
reachableChannels summaryHuman-readable opportunity signals + suggested offerService-area vs storefront, closed status
Per-field fieldSources provenanceNew-lead flag across runsDirect Google Maps link

Detail mode is the default and fills every column above. ⚑ Lite mode skips the place pages and leaves some Maps columns empty β€” see the next table.

πŸ—‚οΈ Which mode fills which field

The Actor runs in detail mode by default (skipPlaceDetailPages: false): it opens every place page. ⚑ Lite mode is opt-in (skipPlaceDetailPages: true, via JSON/API) and builds each lead from the search-results list instead.

Field(s)Detail mode (default)⚑ Lite mode
businessName, category, website, googleMapsUrl, placeId, cid, latitude, longitude, businessStatusβœ…βœ…
phoneβœ…βœ… when the result card shows it
rating, reviewCount, openNowβœ…βœ… when the result card shows them
categoriesβœ… primary + any secondary Google exposesprimary only
address, streetβœ… full addressstreet part only (as the card shows it)
city, state, postalCode, countryβœ… parsed from the full addressonly city/country (+ US state), and only from your optional locations input β€” tagged derived in fieldSources
plusCode, openingHours, priceLevel, attributes, serviceAreaBusiness, claimedByOwnerβœ…βŒ null / []
unclaimedGoogleProfile (and the onlyUnclaimed filter)βœ…βŒ always false β€” the flag only exists on place pages, so onlyUnclaimed switches detail mode on automatically
Website enrichment: emails, socialLinks, linkedinUrl/instagramUrl/facebookUrl, contactPageUrl, websiteResolvedUrl, websitePlatform, techStack, bookingLinkFound, bookingLinks, decisionMakerHintβœ…βœ… identical
Scores & signals: leadScore, leadQuality, the three sub-scores, reachableChannels, opportunitySignals, suggestedOffer, vertical, isNewLeadβœ…βœ… (sub-scores are lower when detail-only fields are missing)
fieldSources, searchQuery, scrapedAtβœ…βœ…

A detail-mode lead whose place page kept failing is salvaged from its search-result card, so that one row carries the lite-mode fields.

πŸ† Why this instead of a plain Google Maps scraper?

Generic Maps scraperThis Actor
Emails from business websitesβŒβœ… incl. obfuscated, Cloudflare-protected, JSON-LD
Lead scoring & prioritizationβŒβœ… 0–100 score + subscores
Unclaimed Google profile detectionβŒβœ… the #1 signal for local SEO sales
Booking-system detectionβŒβœ… 35+ platforms
Website platform detectionβŒβœ… pitch redesigns to Wix/Weebly sites
"Only new leads since last run"βŒβœ… built-in history tracking
Closed-business filteringβŒβœ… on by default
Sales-ready suggested offerβŒβœ… per vertical

πŸ‘₯ Who is it for?

  • Local SEO & GBP agencies β€” filter to onlyUnclaimed profiles and pitch profile management
  • Web design agencies β€” filter to onlyMissingWebsite, or target Wix/Weebly sites for redesigns
  • Booking/SaaS vendors β€” filter to onlyMissingBookingLink in booking-heavy verticals
  • Reputation management β€” filter to maxRating: 4 with minReviewCount: 20
  • Sales teams & consultants β€” export scored, deduplicated prospect lists to any CRM
  • Anyone monitoring a market β€” schedule weekly runs with onlyNewLeads to catch new openings

πŸš€ How to use it (3 steps)

  1. Enter search terms and locations β€” e.g. dentists + Riga, Latvia. Multiple terms Γ— multiple cities are combined automatically.
  2. Run it. The Actor searches Google Maps, opens every place, visits each business website, and scores every lead.
  3. Export β€” download CSV/Excel/JSON from the dataset, or pipe leads into Sheets, your CRM, or 6,000+ apps via integrations.

Example input (that's the whole thing)

{
"searchTerms": ["dentists in Austin, Texas", "HVAC contractors in Phoenix, Arizona"],
"maxResults": 100
}

You can also paste Google Maps URLs directly into startUrls (search URLs, place URLs, or ?cid=... links).

Example output (one real lead, default detail mode)

Taken unchanged from the 2026-09-27 benchmark run (only the whitespace is compacted):

{
"businessName": "ATX Family Dental",
"phone": "+15127173147",
"website": "https://www.atxfamilydental.com",
"emails": ["info@atxfamilydental.com"],
"websiteDomain": "atxfamilydental.com",
"leadScore": 100,
"leadQuality": "very_high",
"rating": 4.9,
"reviewCount": 909,
"category": "Dentist",
"vertical": "dentists",
"city": "Austin",
"state": "TX",
"country": "United States",
"googleMapsUrl": "https://www.google.com/maps/place/ATX+Family+Dental/data=!4m7!3m6!1s0x8644b4eb0b01986f:0x6b241d4769ed491e!8m2!3d30.2482229!4d-97.7559705!16s%2Fg%2F11cn2mvqwc!19sChIJb5gBC-u0RIYRHkntaUcdJGs",
"businessStatus": "operational",
"unclaimedGoogleProfile": false,
"claimedByOwner": true,
"decisionMakerHint": { "name": "Dr. Adam Gutwein", "title": "DMD" },
"socialLinks": {
"facebook": [], "instagram": ["https://www.instagram.com/atxfamilydental"], "linkedin": [],
"youtube": [], "tiktok": [], "x": [], "twitter": [], "pinterest": [], "whatsapp": []
},
"websitePlatform": "WordPress",
"techStack": ["WordPress", "WordPress plugins"],
"bookingLinkFound": true,
"suggestedOffer": "Patient acquisition, local SEO, and booking automation",
"isNewLead": true,
"placeId": "ChIJb5gBC-u0RIYRHkntaUcdJGs",
"cid": "7720327853776914718",
"address": "1700 S 1st St, Austin, TX 78704, United States",
"street": "1700 S 1st St",
"postalCode": "78704",
"latitude": 30.2482229,
"longitude": -97.7559705,
"plusCode": "66XV+7J Austin, Texas, USA",
"categories": ["Dentist"],
"openNow": false,
"openingHours": [
"Sunday Closed", "Monday 8 am–5 pm", "Tuesday 8 am–5 pm", "Wednesday 8 am–5 pm", "Thursday 8 am–5 pm",
"Friday 8 am–4 pm", "Saturday Closed"
],
"priceLevel": null,
"attributes": ["Wheelchair accessible entrance", "LGBTQ+ friendly", "Identifies as women-owned"],
"serviceAreaBusiness": false,
"reachabilityScore": 100,
"reputationScore": 99,
"completenessScore": 100,
"reachableChannels": ["phone", "email", "website"],
"opportunitySignals": [
"Website found", "Email found", "Phone found", "Booking link found", "Instagram found",
"High review count", "New lead", "Contactable lead", "Strong local business",
"Patient acquisition opportunity", "Clinic has contact email"
],
"websiteResolvedUrl": "https://www.atxfamilydental.com/",
"contactPageUrl": "https://www.atxfamilydental.com/contact/",
"linkedinUrl": null,
"instagramUrl": "https://www.instagram.com/atxfamilydental",
"facebookUrl": null,
"bookingLinks": ["https://flexbook.me/atxfd/website"],
"searchQuery": "dentists in Austin, Texas",
"fieldSources": {
"businessName": "maps", "phone": "maps", "website": "maps", "emails": "website",
"websiteDomain": "derived", "leadScore": "derived", "leadQuality": "derived", "rating": "maps",
"reviewCount": "maps", "category": "maps", "vertical": "derived", "city": "maps", "state": "maps",
"country": "maps", "googleMapsUrl": "maps", "businessStatus": "maps", "unclaimedGoogleProfile": "maps",
"claimedByOwner": "maps", "decisionMakerHint": "website", "socialLinks": "website",
"websitePlatform": "website", "techStack": "website", "bookingLinkFound": "website",
"suggestedOffer": "derived", "isNewLead": "derived", "placeId": "maps", "cid": "maps", "address": "maps",
"street": "maps", "postalCode": "maps", "latitude": "maps", "longitude": "maps", "plusCode": "maps",
"categories": "maps", "openNow": "maps", "openingHours": "maps", "attributes": "maps",
"serviceAreaBusiness": "maps", "reachabilityScore": "derived", "reputationScore": "derived",
"completenessScore": "derived", "reachableChannels": "derived", "opportunitySignals": "derived",
"websiteResolvedUrl": "website", "contactPageUrl": "website", "instagramUrl": "website",
"bookingLinks": "website"
},
"scrapedAt": "2026-09-27T13:44:12.003Z"
}

fieldSources tags every non-empty field: maps (from Google Maps), website (scraped from the business site), or derived (computed by the Actor, or taken from your locations input). A field with no entry is null/empty β€” the data wasn't publicly available, never a guess. linkedinUrl / instagramUrl / facebookUrl are the first profile of each network in socialLinks.

πŸ“Š How the lead score works (auditable, not magic)

Every lead is scored on three independent 0–100 sub-scores, all emitted on the record, then blended into the headline leadScore:

reachabilityScore β€” can you contact them right now?

SignalPoints
Email found+40
Phone found (Maps or website)+30
Website found+15
Contact page found+8
Social profile found+7

reputationScore β€” is it an established, trustworthy business? Rating (scaled), review volume (log scale), and owner-claimed status. No rating data β†’ a neutral-low floor so new-but-contactable businesses aren't buried.

completenessScore β€” how fully populated is the record (a proxy for data confidence): name, category, city, phone, website, email, contact page, social, decision-maker, rating, open-now, geo.

leadScore = round(0.45 Γ— reachability + 0.30 Γ— reputation + 0.25 Γ— completeness)

Reachability is weighted highest: a lead you can't contact is worthless no matter how reputable. (In the benchmark, leadScore equals this formula on 80 of 80 records.)

leadQualityRange
low0–39
medium40–69
high70–84
very_high85–100

πŸ†• Monitoring mode: only new leads, every week

  1. Set a stable historyKey per campaign, e.g. dentists-riga.
  2. Enable onlyNewLeads.
  3. Schedule the Actor (e.g. every Monday) under Schedules in the Apify Console.

Each run only outputs businesses never delivered before with that key β€” perfect for catching newly opened businesses or keeping outreach lists fresh. isNewLead means "never appeared in your dataset for this history key".

βš™οΈ Input β€” just three things

The input is intentionally minimal. Everything else is tuned for you to deliver maximum data per lead.

FieldTypeDefaultDescription
searchTermsarray["dentists in Austin, Texas"]What to find β€” one per line; put the location in the line for the simplest setup
locationsarrayβ€”Optional. Cities to combine with every term (skip if terms already include the location)
maxResultsinteger50How many fully-enriched leads to collect
startUrlsarrayβ€”Optional. Direct Google Maps search/place URLs

Everything is on by default: detail pages, website enrichment, email extraction, socials, booking detection, decision-maker hints, tech stack, lead scoring, the reachability gate, closed-business filtering, and new-lead tracking (the history key is derived from your query automatically). The vertical scoring template is auto-detected per business.

πŸ“€ Export & API

Download the dataset as CSV, Excel, JSON, XML, or HTML from the run's Dataset tab β€” or fetch it programmatically:

$curl "https://api.apify.com/v2/datasets/[DATASET_ID]/items?format=csv&token=[YOUR_TOKEN]"
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('glasswing/google-maps-leads-2-49-1k').call({
searchTerms: ['plumbers'],
locations: ['Manchester, UK'],
maxResults: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Got ${items.length} leads`);

A machine-readable run summary (places found, leads saved, filtered counts, billable events) is stored in the run's key-value store under RUN_SUMMARY.

πŸ”Œ Integrations

Connect the Actor to Google Sheets, HubSpot, Pipedrive, Airtable, Slack, and 6,000+ apps using Apify integrations with Make, Zapier, or n8n β€” or trigger webhooks when a run finishes. Typical flow: Schedule β†’ run Actor β†’ append new leads to a sheet β†’ notify Slack.

πŸ›‘οΈ 100% proxy-free by design

This Actor needs no proxies β€” there is nothing to configure. It stays reliable without them like this:

  1. Detail mode (default) β€” one Google request per business, spread over a small, block-tested concurrency. It returns every field in this README.
  2. Automatic cooldowns β€” when Google does rate-limit a request, the Actor pauses with exponential backoff (15s β†’ 120s) and retries with a fresh browser fingerprint instead of failing the run.
  3. Lead salvage β€” every place request carries the data already captured from its search-result card. If a place page keeps failing, the lead is delivered from that data instead of being lost (marked in the log as salvaged; it carries the lite-mode fields).
  4. ⚑ Lite mode (opt-in) β€” set skipPlaceDetailPages: true to build leads directly from the search results list: ~1 Google request per ~100 businesses instead of one per business, so there is almost nothing to rate-limit. Website enrichment, emails, social links, booking detection, and lead scoring all still work in full (they never touch Google); the place-page-only fields in the table above stay empty. Use it for very large volumes; onlyUnclaimed always forces detail mode.

πŸ’° Pricing events

You pay for one thing only: each lead saved to the dataset (Business lead, charged once per row). Places that are filtered out, duplicates, and unreachable businesses are never charged. The count is also reported in RUN_SUMMARY.billableEvents, so you can audit every run.

When your run's maximum charge covers fewer leads than maxResults, the Actor stops at the number of leads it covers. You keep everything collected up to that point.

🚦 Troubleshooting

SymptomFix
Run fails with "Google blocked every request"Switch to ⚑ lite mode (skipPlaceDetailPages: true), set speedMode: "safe", lower maxResults β€” or simply retry later; Google rate limits are temporary
Detail mode keeps pausing on cooldownsThat's the built-in rate-limit handling. Use lite mode for large volumes and detail mode for smaller, field-complete batches
Fewer leads than maxResultsGoogle Maps caps a single search at ~120 results β€” add more specific search terms or split the area into districts
Few emails foundRaise maxPagesPerWebsite to 8–10; disable genericEmailsOnly to keep all addresses
Non-English categories/addressesKeep language: "en"; data language follows Google's localization
address is nullThe business is service-area only (serviceAreaBusiness: true) and publishes no street address β€” add a locations input if you want city/country filled from your search area
A specific page failedBlocked-page screenshots are saved to the key-value store under BLOCKED_* keys

This Actor collects publicly available business information only β€” the same data anyone sees on Google Maps and public websites. It does not log in, does not bypass CAPTCHAs, does not collect reviewer/personal data, and extracts emails only when businesses publish them. With genericEmailsOnly (default) you receive role inboxes (info@, office@) rather than personal addresses, which keeps B2B outreach in most jurisdictions on safe ground. You are responsible for complying with the laws that apply to you (e.g. GDPR, CAN-SPAM) and with how you use the data.

❓ FAQ

How many leads can I get per search? Google Maps returns up to ~120 places per search query. To cover a whole city, add several specific terms (dentist, dental clinic, orthodontist) and/or district-level locations β€” every combination runs as its own search and results are deduplicated automatically.

Does it verify email deliverability? No β€” emails are extracted as published. Pipe the dataset through an email verifier before large campaigns.

Can it find businesses without websites? Yes β€” enable onlyMissingWebsite. Those leads still include phone, address, and Maps data.

What does the unclaimed-profile flag mean? Google shows "Claim this business" on profiles no owner has verified. These businesses rarely respond to their Google reviews, often have outdated info β€” and are the easiest local SEO sale there is.

Does it support scheduling? Yes β€” create a Schedule in the Apify Console. Combine with onlyNewLeads + historyKey to get only fresh leads each run.

What if Google changes its layout? Extraction uses several independent strategies (DOM, URL identifiers, page metadata) with fallbacks. If you spot a regression, open an issue on the Actor page β€” a run with includeRawPlaceData: true adds a rawPlaceData diagnostics object to each row that helps a lot.

πŸ“ Changelog

See ./CHANGELOG.md for release notes. Built with Crawlee + Playwright.


Feedback or feature requests? Open an issue on the Actor's page β€” feedback directly shapes the roadmap. If this Actor saves you time, a ⭐ review helps a lot.