Local Business Lead Finder
Pricing
from $0.50 / 1,000 lead extracteds
Local Business Lead Finder
Discover, extract, and enrich local business leads from Google Maps. Find businesses by keyword and location, collect contact details, emails, and social profiles, and export clean, deduplicated data. Built for automation, CRMs, and recurring lead generation workflows.
Pricing
from $0.50 / 1,000 lead extracteds
Rating
0.0
(0)
Developer
Solutions Smart
Maintained by CommunityActor stats
1
Bookmarked
108
Total users
2
Monthly active users
6 days ago
Last modified
Categories
Features
Share
Local Business Lead Finder: Google Maps scraper with email extraction
Local Business Lead Finder pulls local business leads from Google Maps and adds the emails and social links it finds on each business's website. You enter search terms such as "dentist" or "pizza" and a city or coordinates. The Actor returns names, addresses, phone numbers, websites, ratings and Google Maps links, and in deep mode it also visits each website to look for contact details.
Use it to build sales prospect lists, outreach lists, local SEO research and CRM imports. It removes duplicates across runs, so a scheduled run only adds businesses you have not seen before. Results go to the run's dataset, to your webhook, or to Google Sheets.
If the Actor saves you time, a 5-star review helps me keep improving it.
What can Local Business Lead Finder do?
- Find businesses on Google Maps by keyword and location. A location can be a city or country, or a latitude, longitude and radius.
- Read each place's name, address, phone, website, category, rating, review count, coordinates and Google Maps URL.
- Visit business websites (optional) and follow contact, about and legal notice pages to collect emails, extra phone numbers and social profiles on Facebook, Instagram, LinkedIn, X (Twitter), TikTok and YouTube.
- Score every email it finds, so you can see which addresses belong to the business's own domain and which come from free mail providers.
- Search a whole city in several map views ("city tiles") instead of one result list, to find more businesses than a single Google Maps list shows.
- Remove duplicates by place ID, website or phone, within a run and across scheduled runs.
- Send results to the dataset (the Output tab in Apify Console), to a webhook URL in batches with retries, and to Google Sheets through solutionssmart/google-sheets-integration.
- Make smarter place and contact decisions (optional). With a TypeSafe API key, the Actor tells directories and government listings apart from local businesses, picks which contact page to open next, and records the page each email came from. Without a key, it uses built-in rules.
Running on Apify gives you monitoring, API access, scheduling, storage and integrations with n8n, Make and Zapier.
What data can Local Business Lead Finder extract?
| Field | Description |
|---|---|
| name | Business name |
| address | Full address |
| phone | Phone number from Google Maps |
| phones | Extra phone numbers found on the website (deep mode) |
| website | Business website |
| googleUrl | Google Maps URL |
| category | Primary category |
| lat, lng | Coordinates |
| placeId | Stable Google Maps place identifier |
| rating, reviewCount | Rating and number of reviews, when Google Maps shows them |
| emails | Cleaned emails from the business website (deep mode) |
| emailQuality | A score for each email: confidence, whether the domain matches the website, free or disposable provider, and optional MX check. A high score is not proof that a mailbox works. |
| socials | Facebook, Instagram, LinkedIn, X (Twitter), YouTube and TikTok profiles, plus contact and legal pages on the business's own site |
| placeJudge | Labels for listing type (local business or directory), branch or standalone, area fit, and the chosen email with the page it was found on |
| enrichment | Website visit details, including review flags for sites that publish no email |
| leadScore | Score from 0 to 100 and grade from A to F, based on rating, review count, website and social presence |
| value | Numeric lead value from 0 to 100, taken from leadScore.score |
| isNew | true if this run found the business for the first time |
| tileId | The city tile that found the business (city tiles mode) |
| fetchedAt | ISO timestamp |
How do I get local business leads from Google Maps?
- Open the Actor on Apify and go to the Input tab.
- Add Search Queries (for example
dentist,dental clinic). Then fill in either Locations (Text) (for exampleBerlin, Germany) or Location (Lat/Lng) with a latitude, longitude and radius. - To collect emails and social links, set Mode to Deep and turn on Enrich With Website Data.
- Optionally paste a TypeSafe API Key for smarter place and contact decisions. Leave it empty to use the built-in rules.
- Click Start. Results appear in the Output tab. Use Schedule to refresh your leads regularly.
You can run the Actor from the form in Apify Console without writing code. For automation, use the Apify API, or set webhookUrl to push results to your CRM or workflow.
Example: as many childcare leads as possible in Wiesbaden
Search for Kinderbetreuung, KindertagesstΓ€tte and Tagesmutter in Wiesbaden, Germany. Choose German, Deep mode and Enrich With Website Data. Set Max Results Total and Max Websites To Enrich to 120, Email Scan Depth to 2 and Max Run Time to 1,800 seconds. Set Search Area Coverage to City tiles, so the search covers several nearby map views instead of one list. Choose place-based duplicate removal and turn Output Only New Items off for a fresh comparison. Leave the other settings unchanged.
This run finds more businesses and checks their websites for contact details, so it takes longer and costs more than a short search. The number of businesses and emails depends on what the businesses publish, and neither is guaranteed. General addresses such as info@ can still be useful. A role-address warning does not mean the address is invalid.
If you also want to keep a parent organization's address found on the website when the business has no email on its own domain, set Email Domain Policy to Prefer own domain. The Actor flags those addresses. Own domain only, the default, keeps only matching-domain emails.
Input
The Input tab shows the full schema. You need queries and either locations or geo.
| Parameter | Type | Default | Description |
|---|---|---|---|
| queries | array | required | Search terms, for example ["dentist", "pizza"]. |
| locations | array | - | Text locations, for example ["Berlin, Germany"]. |
| geo | object | - | Latitude, longitude and radius in km. |
| maxResultsTotal | integer | 10 | Maximum unique businesses for the whole run. |
| language | string | "en" | Google Maps language. |
| includeClosed | boolean | false | Include businesses marked as permanently closed. |
| mode | string | "fast" | fast extracts leads only. deep adds website enrichment within the limits you set. |
| enrichWebsite | boolean | false | Visit websites to collect emails, extra phone numbers, a missing street address, contact forms and social links. Used only in deep mode. |
| emailScanDepth | integer | 1 | Number of internal pages, such as /contact, to scan for emails on each website. |
| maxWebsitesToEnrich | integer | 25 | Maximum unique websites to visit in deep mode. |
| maxRunTimeSec | integer | 120 | Time budget for the whole run. The run stops cleanly and keeps finished leads when it runs out. |
| searchAreaCoverage | string | "singleView" | singleView runs one map search per query and location. cityTiles splits a city into several nearby map views and finds more businesses than one list shows. City tiles need a longer Max Run Time. Short searches stay on a single view. |
| emailMxCheck | boolean | false | Check MX records for email domains. Raises confidence but adds DNS lookups and run time. |
| emailDomainPolicy | string | "ownDomainOnly" | ownDomainOnly keeps emails on the business's own domain. preferOwn also keeps a flagged parent-organization address when no own-domain email exists. |
| dedupeBy | string | "placeId" | Duplicate key: placeId, website or phone. |
| newOnlyOutput | boolean | true | If true, output only businesses not seen in earlier runs. If false, output every unique business from this run and mark it with isNew. |
| webhookUrl | string | - | URL that receives results by POST, in batches. Stored encrypted. |
| batchSize | integer | 50 | Number of items per webhook call. |
| googleSheetsSpreadsheetId | string | - | Spreadsheet ID or URL for the Google Sheets export. Leave empty to skip. |
| googleSheetsSheetName | string | "Leads" | Worksheet tab for the export. |
| googleSheetsOperation | string | "APPEND" | APPEND adds rows, REPLACE rewrites the tab, UPSERT updates rows matched by googleSheetsUpsertKey. |
| googleSheetsUpsertKey | string | "placeId" | Field that matches existing rows for UPSERT. |
| resourceProfile | string | "auto" | Memory preset: auto, low (2 GB), standard (2 to 4 GB), high (4 GB or more). auto reads the run memory and suits most runs. |
| detailConcurrency | integer | (from profile) | How many Google Maps place pages to open at once. Leave empty to use the resource profile. |
| enrichmentConcurrency | integer | (from profile) | How many websites to visit at once during enrichment. Leave empty to use the resource profile. |
| proxyMode | string | "unblocker" | Recommended for reliable runs. none turns the proxy off. A proxy adds Apify platform costs. |
| proxyCountryCode | string | - | Optional two-letter country code, such as DE or US. Leave empty to let Apify choose. |
| typesafeApiKey | string | - | Optional key for smarter place and contact decisions. Leave empty to use the built-in rules. |
| judgeShardCount | integer | - | Work Split Count: number of parallel runs that share one search. |
| judgeShardIndex | integer | - | Work Split Index: this run's slot, from 0 to Work Split Count minus one. |
| debug | boolean | false | Verbose logging, including URLs and business details. Turn on only when needed. |
The prefilled example finds three dentists in Berlin in fast mode with a 120-second limit. Without a maximum result count, the Actor returns ten. If the run hits its time limit, it still saves the leads it finished. If Google Maps cannot be reached, the run fails instead of reporting an empty success.
Proxy
The default proxy setting is the recommended one. Choosing a country is optional. A proxy adds Apify platform costs, so pick Direct only if you want proxying off.
Example input
{"queries": ["dentist", "dental clinic"],"locations": ["Berlin, Germany"],"maxResultsTotal": 10,"mode": "fast","enrichWebsite": false,"emailMxCheck": false,"dedupeBy": "placeId","newOnlyOutput": true}
With coordinates:
{"queries": ["cafe"],"geo": { "lat": 52.52, "lng": 13.405, "radiusKm": 5 },"maxResultsTotal": 10}
With performance options. Match Resource profile to the memory you give the run, or leave it on auto:
{"queries": ["dentist"],"locations": ["Berlin, Germany"],"maxResultsTotal": 10,"mode": "deep","maxWebsitesToEnrich": 25,"maxRunTimeSec": 120,"resourceProfile": "high","enrichWebsite": true}
Output
Results go to the run's default dataset and show in the Output tab. You can download them as JSON, CSV, Excel and other formats from the dataset page. Every item has isNew, leadScore and emailQuality, so you can sort and filter leads quickly. The Review Queue dataset view lists sites flagged in enrichment.reviewFlags, such as no_email_exposed_after_browser_fallback.
Export leads to Google Sheets
Set Google Sheets Spreadsheet ID, and optionally a sheet name and operation. When the run finishes, the Actor exports its dataset to your spreadsheet through solutionssmart/google-sheets-integration.
- Enable the Google Sheets API in a Google Cloud project and create a service account.
- Share the spreadsheet with the service account's
client_email, with Editor access. - Paste the spreadsheet ID or URL into Google Sheets Spreadsheet ID and choose a Sheets Operation (
APPEND,REPLACEorUPSERT). - Start the run. The Actor writes the leads to the sheet when the run finishes.
Example:
{"queries": ["dentist"],"locations": ["Berlin, Germany"],"maxResultsTotal": 10,"mode": "fast","googleSheetsSpreadsheetId": "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms","googleSheetsSheetName": "Leads","googleSheetsOperation": "APPEND"}
The export never blocks or fails the lead run, even if Google Sheets is unreachable. Every lead has a placeId, so UPSERT updates matching rows instead of adding duplicates.
Example output item
{"placeId": "0x47a84e339e1b3e6f:0xa3449be1eb562cf5","name": "Kottident - Dentist in Berlin Kreuzberg","address": "Adalbertstrasse 94, 10999 Berlin, Germany","category": "","phone": "+49 30 3911155","website": "http://www.kottident.de/","googleUrl": "https://www.google.com/maps/place/Kottident+-+Dentist+in+Berlin+Kreuzberg/data=!4m7!3m6!1s0x47a84e339e1b3e6f:0xa3449be1eb562cf5!8m2!3d52.5007495!4d13.4187246!16s%2Fg%2F1v_sm8bx!19sChIJbz4bnjNOqEcR9SxW6-GbRKM?authuser=0&hl=en&rclk=1","lat": 52.5007495,"lng": 13.4187246,"rating": "4.7","reviewCount": "","discoverySource": "detail","fetchedAt": "2026-03-22T22:45:15.688Z","isNew": true,"emails": ["info@kottident.de"],"socials": {"facebook": "https://www.facebook.com/kottident","other": ["http://kottident.de/contact.html","https://www.kottident.de/index%20-%20english.html"]},"enrichment": {"websiteVisited": true,"scannedUrl": "https://www.kottident.de/impressum.html"},"emailQuality": {"bestEmail": "info@kottident.de","bestScore": 72,"averageScore": 72,"highConfidenceCount": 0,"mediumConfidenceCount": 1,"lowConfidenceCount": 0,"assessments": [{"email": "info@kottident.de","accepted": true,"selected": true,"syntaxValid": true,"syntaxScore": 100,"score": 72,"confidence": "medium","domain": "kottident.de","domainMatchesWebsite": true,"domainDistance": 0,"roleBased": true,"freeProvider": false,"disposableProvider": false,"mxValid": null,"reasons": ["role_based", "domain_matches_website"]}],"rejected": [],"selectedEmails": ["info@kottident.de"],"telemetry": {"totalCandidates": 20,"acceptedCount": 2,"rejectedCount": 0,"topRejectionReasons": [],"domainMatchedPercent": 100,"malformedPatternCounters": {}}},"leadScore": { "score": 72.6, "grade": "B" },"value": 72.6}
Example of a lead flagged for manual review
{"name": "Example Clinic Without Public Email","website": "https://example-clinic.com","emails": [],"enrichment": {"websiteVisited": true,"scannedUrl": "https://example-clinic.com/impressum","browserFallbackExhausted": true,"reviewFlags": ["no_email_exposed_after_browser_fallback"]}}
How does the Actor clean extracted emails?
Text scraped from websites often glues an email to a phone number, a URL or the next word. The Actor cleans each address, checks its syntax and keeps only valid ones in emails.
emailsholds only normalized, syntax-valid addresses with no glued phone numbers, URLs or text.- When
emailsis not empty,emailQuality.bestEmailis always one of its entries. emailQuality.assessmentslists accepted and rejected candidates with their reasons, for debugging.emailQuality.rejectedlists each rejected address as{ email, reasons[] }.emailQuality.telemetrycounts candidates, rejections, the share of emails matching the website domain, and malformed patterns.
Raw text from a website:
{"emails": ["4445656info@zahnarztmichael.dewww.zahnarztmichael.de","praxis@schoene-zaehne-berlin.deweb"]}
What the Actor returns:
{"emails": ["info@zahnarztmichael.de","praxis@schoene-zaehne-berlin.de"],"emailQuality": {"bestEmail": "info@zahnarztmichael.de","rejected": [{"email": "4445656info@zahnarztmichael.dewww","reasons": ["numeric_prefix_pollution", "trailing_word_after_tld"]}]}}
How much does it cost to get local business leads with this Actor?
The Actor uses pay-per-event pricing with two events:
lead-extracted: $3.50 to $5 per 1,000 new unique leadswebsite-enriched: $8 to $12 per 1,000 leads where website enrichment found an email
The Actor charges lead-extracted after it writes a new, unique, in-area, non-empty lead to the dataset. It charges website-enriched only when enrichment finds at least one email. Phone numbers, social links or a contact form without an email do not trigger website-enriched. Fast mode runs usually trigger only lead-extracted. In deep mode with enrichWebsite: true, only leads with an email trigger both events.
For the cheapest lead-only runs, use mode: "fast". To cap the cost of deep runs, set maxResultsTotal, maxWebsitesToEnrich and maxRunTimeSec.
What you are never charged for
- Results with no address, phone or website
- Sponsored ads
- Duplicates
- Businesses outside the area you searched
- Website enrichment that finds no email
Each run saves a short summary of how many leads were requested, returned and skipped. Platform compute and proxy usage can still appear on the run's Usage tab.
Use cases
- Sales teams and agencies: build prospect lists of local businesses such as plumbers, restaurants and clinics, with phone numbers, websites and emails.
- Local SEO: research competitors and how many businesses of a type operate in an area.
- Market research: track businesses by location, optionally including permanently closed ones.
- CRM pipelines: send leads to HubSpot, Salesforce, Pipedrive or any system that accepts webhooks.
- Scheduled lead refresh: run on a schedule and get only businesses that earlier runs did not find.
Tips
- Memory and resource profile. Runs default to 2 GB of memory and usually peak around 0.8 GB. Set Resource profile (memory) to match the memory you give the run (2 GB is Low, 4 GB or more is High). The profile tunes concurrency for speed or memory use. Detail concurrency and Enrichment concurrency give finer control.
- Google Maps. The Actor drives a real browser on Apify. Use the recommended resources for production runs. Changes to Google's consent page or Maps layout can occasionally affect results.
- Enrichment. The Actor follows only links on the business's own domain and its subdomains, and visits contact-style paths such as /contact and /about first.
- Email checks. Turn on emailMxCheck only when you need stronger email confidence. It adds DNS lookups and run time.
- Webhooks. Batches that still fail after retries show up in the run log, so you can resend them yourself.
- API and integrations. Start runs and fetch results through the Apify API, or set webhookUrl to push leads straight to n8n, Make, Zapier or your own endpoint.
- Splitting a large search. Set Work Split Count to the number of parallel runs and Work Split Index to each run's slot, starting at 0. Each city tile and each listing is then handled by one run only. Leave both empty to handle everything in a single run.
FAQ
Can I scrape emails from Google Maps?
Google Maps does not show email addresses. In deep mode with Enrich With Website Data on, the Actor visits each business's website and collects the emails published there, such as on the contact or legal notice page.
Why do some leads have no email?
Many local businesses publish only a phone number or a contact form. The Actor reports what the website shows and flags sites with no public email for review. You are not charged website-enriched for those leads.
How do I get only new businesses on each run?
Keep Output Only New Items on and run the Actor on a schedule. It skips businesses that earlier runs already found, based on the duplicate key you choose.
How do I find more businesses in a big city?
Set Search Area Coverage to City tiles and give the run a longer Max Run Time. The Actor then searches several nearby map views instead of one result list.
Can I export Google Maps leads to CSV or Excel?
Yes. Download the dataset as CSV, Excel or JSON from the Output tab, or export straight to Google Sheets.
Compliance, disclaimers and support
Use this Actor only for legitimate lead generation and research. Get consent or have a lawful basis, such as legitimate interest, before you contact businesses. You are responsible for following GDPR, CAN-SPAM and local rules when you use extracted emails or phone numbers.
A published contact address is not consent to receive advertising. General addresses such as info@ can still be useful for a local business, and a role-address label does not mean the address is invalid. Decision confidence describes the evidence. It does not check whether a mailbox exists.
Smarter place and contact decisions (optional)
With an optional TypeSafe API key, the Actor decides which listings are real local businesses, which page on the website to open next, and which published email to keep, along with the page where it found the address. Without a key, it uses built-in rules. It drops directory, government and aggregator listings only when that decision has high confidence, and keeps uncertain rows for review. It flags nearby, borderline areas instead of dropping them. Map coordinates and radius still decide which places are out of area.
If you run into a problem, check the Input tab and this README first. Report bugs and feature requests in the Issues tab on the Actor page. For custom solutions based on this Actor, contact the creator through the Actor profile.