Lead Enricher for Google Maps
Pricing
from $5.00 / 1,000 enriched results
Lead Enricher for Google Maps
Enrich Google Maps leads with emails, phones, social profiles, decision makers and tech stack from each business website — plus a 0–100 lead score that explains why each lead is worth calling.
Pricing
from $5.00 / 1,000 enriched results
Rating
0.0
(0)
Developer
Mapwise Data
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Turn a raw Google Maps export into a ranked call list — emails, phones, socials, decision makers, tech stack and a 0–100 lead quality score for every business.
A Google Maps scraper gives you names, ratings and websites. It does not tell you who to email, what their site runs on, or which of the 800 rows is worth your morning. Lead Enricher for Google Maps crawls each business website over plain HTTP, pulls out everything a salesperson needs, and scores each lead so the best opportunities float to the top.
No headless browser, no SMTP probing, no guesswork: just fast Cheerio parsing and a transparent scoring model that tells you exactly why a lead scored what it did.
What you get
One dataset row per business. Here is a real-shaped record for a dental practice whose site is stuck on Wix and has no booking tool:
{"id": "b17","name": "Riverside Dental Practice","website": "riversidedental.co.uk","normalizedWebsite": "https://riversidedental.co.uk","phone": "+44 161 496 0000","phones": ["+441614960000", "+441614960011"],"emails": [{"address": "info@riversidedental.co.uk","type": "role","mxValid": true,"sourceUrl": "https://riversidedental.co.uk/contact"},{"address": "j.okafor@riversidedental.co.uk","type": "personal","mxValid": true,"sourceUrl": "https://riversidedental.co.uk/about"}],"socials": {"linkedin": "https://www.linkedin.com/company/riverside-dental","instagram": "https://www.instagram.com/riversidedental","facebook": "https://www.facebook.com/riversidedental","x": null,"tiktok": null,"youtube": null},"people": [{"name": "Joy Okafor","title": "Founder & Principal Dentist","linkedin": "https://www.linkedin.com/in/joy-okafor","sourceUrl": "https://riversidedental.co.uk/about"},{"name": "Mark Reilly","title": "Practice Manager","linkedin": null,"sourceUrl": "https://riversidedental.co.uk/about"}],"techStack": {"cms": "Wix","ecommerce": null,"analytics": [],"chat": [],"booking": [],"payments": ["Stripe"],"other": ["Cloudflare"]},"siteStatus": "live","responseMs": 412,"pagesCrawled": 4,"leadQualityScore": 95,"scoreReasons": ["Low-end site builder","Low rating — reputation risk","No online booking","No live chat","No analytics installed","Direct contact found","Decision maker identified"],"bestFor": ["web-design", "seo", "reputation", "booking-software", "chat-software", "general-outreach"],"daysSinceLastReview": 34,"input": {"rating": 3.2,"reviewsCount": 48,"categoryName": "Dentist","placeUrl": "https://www.google.com/maps/place/Riverside+Dental+Practice"},"enrichedAt": "2026-09-22T09:14:02.118Z"}
You can download the dataset in various formats such as JSON, HTML, CSV, or Excel, or pull it straight from the Apify API.
Use cases
Web design and development agencies. Sort by leadQualityScore and filter on bestFor: "web-design" to get every local business with no website, a dead domain, a parked domain, or a Wix/Weebly/GoDaddy site — with a named decision maker and a verified email attached.
SEO agencies. techStack.analytics being empty is a blunt, honest signal that nobody is measuring anything. Combine it with siteStatus and responseMs for a pitch that writes itself.
Reputation management. Filter on bestFor: "reputation": businesses rated under 3.5 with enough reviews for the rating to be real.
Booking and scheduling software. Restaurants, salons, hairdressers, barbers, clinics, dentists, gyms and spas with nothing in techStack.booking are a category-matched, no-argument pitch.
Live chat and conversational tools. Empty techStack.chat on a live site, with contact details already in hand.
Sales teams qualifying a Google Maps export. Run your scrape, pipe the dataset through this Actor, and hand your SDRs a list that is already ranked, deduplicated by contact, and annotated with why each row is on it.
How to use Lead Enricher for Google Maps
1. Get your businesses. Run a Google Maps scraper such as compass/crawler-google-places and copy the dataset ID from the run's Storage tab. Alternatively, paste business records straight into the businesses input field.
2. Point this Actor at them. Put the dataset ID into datasetId, pick which enrichment steps you want, and click Start. Field names from the common Google Maps scrapers (title, website, totalScore, reviewsCount, categoryName, url) are mapped automatically, so no reshaping is needed.
3. Chain it so it runs by itself. On your Google Maps scraper's run, open Integrations → Connect Actor and select Lead Enricher for Google Maps. Set the input field datasetId to the template variable {{resource.defaultDatasetId}}. Every scrape then enriches itself, and you can schedule the pair to refresh a territory weekly.
Using the API directly? Start a run with the previous run's dataset ID:
curl -X POST "https://api.apify.com/v2/acts/mapwise_data~lead-enricher/runs?token=$APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{ "datasetId": "PREVIOUS_RUN_DATASET_ID", "maxPagesPerSite": 5 }'
Input
| Field | Type | Default | What it does |
|---|---|---|---|
datasetId | string | — | Dataset of a Google Maps scraper run. Every item is treated as one business. When set, businesses is ignored. |
businesses | array | one sample business | Business records pasted directly: { name, website, phone, rating, reviewsCount, categoryName, placeUrl, lastReviewDate }. |
enrich | array | all | Which steps to run: contacts, social, people, techStack, score. Fewer steps, faster runs. |
verifyEmails | boolean | true | Check MX records for each email domain. |
maxPagesPerSite | integer | 5 | Pages per website including the homepage (1–15). |
maxConcurrency | integer | 10 | Parallel page fetches. Lower it to be gentler on target sites. |
proxyConfiguration | object | { "useApifyProxy": true } | Proxy settings. Apify Proxy is recommended. |
Provide either datasetId or businesses. If you provide a datasetId, the businesses field is ignored. A run with no input at all enriches a single sample business, so you can see the output format before connecting your own data.
Output field reference
| Field | Type | Description |
|---|---|---|
id | string | Stable ID for the business within the run. |
name | string | Business name, from name or title. |
website / normalizedWebsite | string | null | The website as given, and after adding a scheme, lowercasing the host and stripping tracking parameters. |
phone | string | null | The phone number from the source record. |
phones | string[] | Numbers found on the website, in E.164 where the country is inferable. |
emails | object[] | { address, type, mxValid, sourceUrl }. type is role (info@, hello@, sales@, …) or personal. |
socials | object | linkedin, instagram, facebook, x, tiktok, youtube — canonical company profile URLs, share/intent links ignored. |
people | object[] | Up to 10 { name, title, linkedin, sourceUrl }, decision makers first. |
techStack | object | { cms, ecommerce, analytics[], chat[], booking[], payments[], other[] }. cms falls back to "custom" when nothing matches. |
siteStatus | string | live, dead, ssl_error, parked, blocked or no_website. |
responseMs | number | null | Homepage response time. |
pagesCrawled | number | How many pages were actually parsed. |
leadQualityScore | number | null | 0–100. null when score is not in enrich. |
scoreReasons | string[] | One human-readable line per scoring rule that fired. |
bestFor | string[] | web-design, seo, reputation, booking-software, chat-software, general-outreach. |
daysSinceLastReview | number | null | Age of lastReviewDate, when the source provided one. |
input | object | The rating, reviewsCount, categoryName and placeUrl we were given. |
enrichedAt | string | ISO timestamp of enrichment. |
Scoring explained
Every lead starts at 50 and each rule that fires moves it, appending its reason to scoreReasons. The final score is clamped to 0–100.
| Rule | Points | Reason |
|---|---|---|
| No website at all | +20 | No website — web design opportunity |
| Site is dead, parked or has a broken certificate | +25 | Website down or parked |
| CMS is Wix, Weebly or GoDaddy | +10 | Low-end site builder |
| Rating below 3.5 with 5+ reviews | +15 | Low rating — reputation risk |
| No booking tool, in a booking-heavy category | +10 | No online booking |
| No live chat widget | +5 | No live chat |
| No analytics installed | +5 | No analytics installed |
| Last review older than 180 days | −10 | Possibly inactive |
| A personal email that passes the MX check | +10 | Direct contact found |
| Someone with a decision-maker title | +10 | Decision maker identified |
| No email, no phone and no socials | −20 | Unreachable |
Two deliberate design choices are worth knowing:
- Rules about what a website lacks (low-end builder, no chat, no analytics) only fire when at least one page was actually fetched. If a site was blocked or dead, we do not pretend to know what it runs.
- "No online booking" also fires for businesses with no website at all, because that is still a real gap in a booking-heavy category.
Booking-heavy categories are matched on categoryName against: restaurant, salon, hairdresser, barber, beauty, nail, spa, massage, clinic, dentist, physiotherapy and other therapy, vet, gym, fitness, yoga and pilates.
Pricing
This Actor uses pay per event, so you pay for results rather than for time:
| Event | When it is charged |
|---|---|
lead_enriched | Once per business successfully written to the dataset. |
email_verified | Once per email address that went through an MX check. |
Businesses that fail because of an error on our side are not charged. Your spending limit is respected: if you set a maximum cost per run, the Actor only enriches as many businesses as that budget covers, and the run's status message tells you how many that was. Set verifyEmails: false to skip MX verification entirely and avoid the second event. Because the crawl is HTTP-only, compute cost is low: a run over 1,000 businesses at maxPagesPerSite: 5 is a few thousand small HTTP requests, not a few thousand browser sessions.
Tips
- Start with
maxPagesPerSite: 3on a large list. The homepage plus a contact and an about page finds most contact details; pages 4 and 5 have diminishing returns. - Trim
enrichif you only need one thing. Running just["contacts", "score"]is meaningfully faster than the full set. - Use Apify Proxy for lists over a few hundred businesses, otherwise shared hosting providers start rate-limiting you and more sites come back
blocked. - Lower
maxConcurrencyif you are enriching many businesses that share one hosting provider.
FAQ
Does it use a headless browser? No. Everything is plain HTTP with Cheerio parsing, which is roughly an order of magnitude cheaper and faster than a browser crawl. The trade-off is that contact details rendered purely by client-side JavaScript are not visible — in practice, contact and team pages are overwhelmingly server-rendered.
Does it verify emails over SMTP? No. We resolve MX records for each email domain and cache the result per domain. No SMTP handshake is opened and no mail is ever sent, so nothing is delivered to the addresses and nothing shows up in anyone's inbox. mxValid: true means the domain can receive mail; it does not prove that specific mailbox exists.
What about sites that block crawlers? They are classified, not dropped. A site that refuses us gets siteStatus: "blocked", and the business is still scored on everything we do know — rating, reviews, category, source phone. Failed DNS or connection gives dead, a certificate problem gives ssl_error, and a domain-parking page gives parked.
What if a business lists a booking page as its website? Many salons and clinics list a Fresha, Treatwell, Booksy or similar page instead of their own site. Those are recognized: the business gets siteStatus: "no_website" (it has no site of its own, which makes it a web-design lead) and the platform is recorded in techStack.booking, so it is not also flagged for missing online booking. NHS, Yell and similar directory listings are treated as no website too.
Which Google Maps scrapers work as a source? Any of them. Field names from compass/crawler-google-places (title, totalScore, reviewsCount, categoryName, url) and common variants are mapped automatically; anything unrecognised falls back to name and website.
Is scraping business websites legal? This Actor reads publicly available pages, respects a one-second delay per domain, and collects business contact information — the kind of details a company publishes precisely so it can be contacted. You are responsible for how you use the output, including compliance with GDPR, CAN-SPAM, PECR and the terms of the sites involved. Do not use it to collect personal data you have no lawful basis to process.
Something is wrong or missing. Open an issue on the Actor's Issues tab. Custom fields, extra tech-stack signatures and different scoring weights are all straightforward to add.
Changelog
0.1.2 — fixes from a pre-launch test on real businesses
Tested end to end on real dentists and hair salons, chained after the Google Maps Scraper exactly as described above.
- Chaining after a Google Maps Scraper run now works. The Actor previously lacked permission to read the scraper's dataset.
- Your maximum cost per run is respected: only as many businesses as the budget covers are enriched.
- A run with no input enriches one sample business instead of failing.
- Businesses whose "website" is a Fresha, Treatwell, Booksy or similar booking page are treated as having no website of their own, with the platform recorded as their booking tool. Directory listings such as NHS and Yell are treated the same way.
- Service names, policies and page sections ("Smile Makeover", "Privacy Policy") are no longer reported as people. Job titles are matched as whole words.
- "Principal" is recognized as a decision-maker title.
- Street numbers are no longer attached to the end of phone numbers.
- Cloudflare-protected email addresses are now decoded; masked placeholders are rejected.
- Department inboxes (directors@, press@, reception@) and role words joined to a business name (infostudioseven@) are classified as shared, not personal.
- Hairdressers, beauty, nails, physio, fitness and similar appointment-based categories now count as booking-heavy.
0.1.1 — accuracy fixes from the first real runs
- Phone numbers are no longer read out of a site's embedded JavaScript data. Modern sites (Next.js and similar) previously produced dozens of fake numbers per page.
- Company registration and VAT numbers are no longer reported as phone numbers.
- Email addresses no longer run into the text of the link next to them.
- Magento is only reported for sites that actually run it, not for pages that mention it or contain images.
- UK and European numbers normalize correctly to E.164, including
+44 (0)…and numbers already written with their country code. - Opening hours and copyright year ranges are no longer mistaken for phone numbers.
- Link labels such as "Connect with Jane" are no longer reported as people.
0.1 — initial release
- Enrichment from a Google Maps dataset ID or inline business records.
- Contact extraction (emails with role/personal classification and de-obfuscation, phones in E.164).
- Company social profiles and personal LinkedIn discovery.
- People and job titles from About/Team pages.
- Tech-stack detection across CMS, e-commerce, analytics, chat, booking and payments.
- Site status classification: live, dead, SSL error, parked, blocked, no website.
- MX-based email verification with per-domain caching.
- 0–100 lead quality score with reasons and
bestForrouting. - Pay-per-event billing:
lead_enriched,email_verified.