Google Maps Leads Extractor & Scraper β Emails | $2.49/1k
Pricing
$2.49 / 1,000 business leads
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
Maintained by CommunityActor 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:
| Metric | Result (detail mode, the default) |
|---|---|
| Records shipped | 80 |
| % with phone β all valid E.164 | 100% |
| % with website | 100% |
| % reachable (phone/email/website) | 100% (hard gate; 0 place-only rows shipped) |
| address / street / city / state / postal / country fill | 99% / 99% / 99% / 99% / 99% / 99% ΒΉ |
| lat-lng / place_id / CID / plus code fill | 100% / 100% / 100% / 99% |
| rating / review count / open-now / opening-hours fill | 100% / 100% / 98% / 93% |
| claimed-by-owner / attributes / tech-stack fill | 100% / 80% / 90% |
| % with email | 44% |
| % with social profile | 83% |
| % with decision-maker hint | 64% |
| contact page / resolved website URL / booking links | 76% / 94% / 53% |
sub-scores, reachableChannels, opportunitySignals, fieldSources | 100% of records |
| Addresses containing button labels or phone numbers | 0 |
| Duplicates shipped (by place_id) | 0 |
| Avg lead score | 84.4 (0 low / 8 medium / 37 high / 35 very-high) |
| Speed | 48β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 label | Name, primary + secondary categories |
| Phone in E.164 (Maps and website) | Reachability / reputation / completeness sub-scores | Full address β street / city / state / postal / country |
| Website + resolved final URL + domain | β Unclaimed Google Business Profile flag | Rating & review count |
| Decision-maker hint (name + title from About/Team) | Tech stack (CMS + analytics/ads/commerce) | Attributes (wheelchair, LGBTQ+, women-owned, β¦) |
| Contact-page deep link | Website platform (WordPress, Wix, Squarespace, β¦) | Open-now, opening hours, price level, plus code |
| Facebook, Instagram, LinkedIn, YouTube, TikTok, X, Pinterest, WhatsApp | Booking-link detection (Calendly, Fresha, OpenTable, Zocdoc + 30 more) | Latitude / longitude, place_id, CID |
reachableChannels summary | Human-readable opportunity signals + suggested offer | Service-area vs storefront, closed status |
Per-field fieldSources provenance | New-lead flag across runs | Direct 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 exposes | primary only |
address, street | β full address | street part only (as the card shows it) |
city, state, postalCode, country | β parsed from the full address | only 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 scraper | This 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
onlyUnclaimedprofiles and pitch profile management - Web design agencies β filter to
onlyMissingWebsite, or target Wix/Weebly sites for redesigns - Booking/SaaS vendors β filter to
onlyMissingBookingLinkin booking-heavy verticals - Reputation management β filter to
maxRating: 4withminReviewCount: 20 - Sales teams & consultants β export scored, deduplicated prospect lists to any CRM
- Anyone monitoring a market β schedule weekly runs with
onlyNewLeadsto catch new openings
π How to use it (3 steps)
- Enter search terms and locations β e.g.
dentists+Riga, Latvia. Multiple terms Γ multiple cities are combined automatically. - Run it. The Actor searches Google Maps, opens every place, visits each business website, and scores every lead.
- 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"}
fieldSourcestags every non-empty field:maps(from Google Maps),website(scraped from the business site), orderived(computed by the Actor, or taken from yourlocationsinput). A field with no entry isnull/empty β the data wasn't publicly available, never a guess.linkedinUrl/instagramUrl/facebookUrlare the first profile of each network insocialLinks.
π 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?
| Signal | Points |
|---|---|
| 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.)
| leadQuality | Range |
|---|---|
low | 0β39 |
medium | 40β69 |
high | 70β84 |
very_high | 85β100 |
π Monitoring mode: only new leads, every week
- Set a stable
historyKeyper campaign, e.g.dentists-riga. - Enable
onlyNewLeads. - 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.
| Field | Type | Default | Description |
|---|---|---|---|
searchTerms | array | ["dentists in Austin, Texas"] | What to find β one per line; put the location in the line for the simplest setup |
locations | array | β | Optional. Cities to combine with every term (skip if terms already include the location) |
maxResults | integer | 50 | How many fully-enriched leads to collect |
startUrls | array | β | 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:
- Detail mode (default) β one Google request per business, spread over a small, block-tested concurrency. It returns every field in this README.
- 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.
- 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).
- β‘ Lite mode (opt-in) β set
skipPlaceDetailPages: trueto 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;onlyUnclaimedalways 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
| Symptom | Fix |
|---|---|
| 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 cooldowns | That's the built-in rate-limit handling. Use lite mode for large volumes and detail mode for smaller, field-complete batches |
Fewer leads than maxResults | Google Maps caps a single search at ~120 results β add more specific search terms or split the area into districts |
| Few emails found | Raise maxPagesPerWebsite to 8β10; disable genericEmailsOnly to keep all addresses |
| Non-English categories/addresses | Keep language: "en"; data language follows Google's localization |
address is null | The 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 failed | Blocked-page screenshots are saved to the key-value store under BLOCKED_* keys |
βοΈ Is it legal?
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.