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
4
Total users
1
Monthly active users
8 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 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.