Google Maps Leads | $2.49 / 1k |
Pricing
$2.49 / 1,000 business leads
Google Maps Leads | $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
2
Total users
0
Monthly active users
a month 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 cloud runs)
Three real queries — dentists in Austin, HVAC contractors in Phoenix, law firms in Miami — run on Apify, proxy-free, detail mode (60 leads):
| Metric | Result (detail mode) |
|---|---|
| Records shipped | 60 |
| % with phone — all valid E.164 | 100% |
| % with website | 100% |
| % reachable (phone/email/website) | 100% (hard gate; 0 place-only rows shipped) |
| street / city / state / postal / country fill | 100% / 100% / 100% / 100% / 100% |
| lat-lng / place_id / plus_code fill | 100% / 100% / 100% |
| rating / review-count / open-now fill | 100% / 97% / 98% |
| claimed-by-owner / attributes / tech-stack fill | 100% / 85% / 88% |
| % with email | 40% |
| % with social profile | 82% |
| % with decision-maker hint | 63% |
| Duplicates shipped (by place_id) | 0 |
| Avg lead score | 83.9 (0 low / 8 medium / 28 high / 24 very-high) |
| Runtime / cost | ~14 min · ≈ $3.25 / 1,000 enriched leads |
Same queries in ⚡ lite mode (fast path): 31 leads in ~1 minute at ≈ $0.45 / 1,000 leads — 100% website, 100% E.164-valid phones, 0 dupes, 0 unreachable shipped — but thinner (no state/attributes; phone and full address only where the card exposes them). 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 only for restaurants/retail). A global maxResults is shared across queries, so a third query can be starved if the first two fill the quota — raise maxResults or run one query per task for even coverage. Fields Google hides from headless browsers (rating distribution, review velocity, popular times) are left null, never faked.
✨ 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, 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 |
Opening hours, plus code, price level, and the unclaimed-profile flag come from place detail pages — turn ⚡ lite mode off to include them (see "100% proxy-free by design" below).
🏆 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, detail mode)
{"businessName": "ATX Family Dental","category": "Dentist","categories": ["Dentist"],"vertical": "dentists","leadScore": 100,"leadQuality": "very_high","reachabilityScore": 100,"reputationScore": 99,"completenessScore": 100,"reachableChannels": ["phone", "email", "website"],"phone": "+15127173147","emails": ["info@atxfamilydental.com"],"website": "https://www.atxfamilydental.com","websiteResolvedUrl": "https://www.atxfamilydental.com/","websiteDomain": "atxfamilydental.com","linkedinUrl": null,"instagramUrl": "https://www.instagram.com/atxfamilydental","facebookUrl": null,"contactPageUrl": "https://www.atxfamilydental.com/contact","decisionMakerHint": { "name": "Dr. Adam Gutwein", "title": "DMD" },"address": "1700 S 1st St, Austin, TX 78704, United States","street": "1700 S 1st St","city": "Austin","state": "TX","postalCode": "78704","country": "United States","latitude": 30.2482229,"longitude": -97.7559705,"plusCode": "66XV+7J Austin, Texas, USA","rating": 4.9,"reviewCount": 841,"businessStatus": "operational","claimedByOwner": true,"serviceAreaBusiness": false,"openNow": false,"attributes": ["Wheelchair accessible entrance", "LGBTQ+ friendly", "Identifies as women-owned"],"websitePlatform": "WordPress","techStack": ["WordPress", "Google Tag Manager", "Meta Pixel"],"bookingLinkFound": true,"bookingLinks": ["https://flexbook.me/atxfd"],"suggestedOffer": "Patient acquisition, local SEO, and booking automation","googleMapsUrl": "https://www.google.com/maps/place/...","placeId": "ChIJb5gBC-u0RIYRHkntaUcdJGs","cid": "7720327853776914718","searchQuery": "dentists in Austin, Texas","fieldSources": {"businessName": "maps", "phone": "maps", "address": "maps", "rating": "maps","emails": "website", "website": "maps", "websiteResolvedUrl": "website","techStack": "website", "decisionMakerHint": "derived", "leadScore": "derived"},"scrapedAt": "2026-06-14T07:00:00.000Z"}
Every field carries provenance in
fieldSources—maps(from Google Maps),website(scraped from the business site), orderived(computed). Anullfield is honest: it means the data wasn't publicly available, never a guess.
📊 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.
| 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: 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('YOUR_USERNAME/google-maps-local-leads-enricher').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. Three layers make that possible:
- ⚡ Lite mode (default) — leads are built directly from the search results list instead of opening every place page. That's ~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).
- 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 — in detail-page mode 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).
Want the extra detail-page fields? Turn lite mode off (skipPlaceDetailPages: false) to add plusCode, openingHours, priceLevel, and unclaimedGoogleProfile — those only exist on detail pages, so that mode sends one Google request per business and relies on the cooldown + salvage layers. The onlyUnclaimed filter switches detail pages on automatically. Everything else — name, category, address, phone, website, rating, review count, coordinates, place ID, and all website enrichment — is identical in both modes.
💰 Pricing events
When the Actor runs under pay-per-event pricing, these events are charged (counts are also reported in RUN_SUMMARY, so you can audit every run):
| Event | Charged when |
|---|---|
place_found | A Google Maps place is discovered and queued |
local_lead | A unique, filtered lead is saved to the dataset |
enriched_lead | The lead's website was successfully enriched |
email_found | The lead includes at least one email address |
The Actor stops gracefully when your run's maximum charge is reached — you keep everything collected up to that point.
🚦 Troubleshooting
| Symptom | Fix |
|---|---|
| Run fails with "Google blocked every request" | Keep ⚡ Lite mode on, set speedMode: "safe", lower maxResults — or simply retry later; Google rate limits are temporary |
| Detail-page 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 |
| 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 — diagnostics from includeRawPlaceData help 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.