Extract Business Leads from Google Maps with Emails — Automated Pipeline with n8n and Apify
Cold outreach only works if you have good data. Most lead lists are outdated, incomplete, or scraped from directories that haven't been maintained in years.
Google Maps is the opposite: it's the most maintained business directory on the planet, updated in real-time by business owners and users. This tutorial shows how to build an automated pipeline that extracts business leads from Google Maps — complete with contact emails scraped from their websites — and delivers them as a clean spreadsheet.
What the Pipeline Extracts
For each business in your search results:
- Business name, category, address
- Phone number
- Website URL
- Google rating and review count
- Opening hours
- Contact emails (scraped from the business website)
- Direct Google Maps URL
A search for "dentistas Madrid" returns 20-50 businesses in one run. A search for "plumbers London" or "restaurants Barcelona" works identically.
Architecture: Two-Phase Extraction
The extraction runs in two phases to handle Google Maps' dynamic JavaScript rendering:
Phase 1 — Search results scraping
Navigate to google.com/maps/search/[query], scroll the results feed to load all listings, collect the URL of each place page.
Phase 2 — Detail page extraction
Visit each place URL individually to extract the structured data (phone, address, website, rating). Then fetch the business website to find contact emails.
This two-phase approach avoids the timeout issues that come from trying to extract everything in one pass on a dynamic-loading page.
The Email Extraction Logic
Emails are scraped from these pages on each business website (in order):
- Homepage
-
/contactor/contacto -
/aboutor/sobre-nosotros
The scraper stops after finding 3 valid emails per domain. It filters out:
- Generic/no-reply addresses (
noreply@,postmaster@, etc.) - System emails (
@sentry.io,@amazonaws.com, etc.) - Placeholder addresses (
@example.com,@yourdomain.com) - False positives from CSS/JS files (e.g.
background.png@)
const SKIP_DOMAINS = [
'example.com', 'sentry.io', 'google.com', 'googleapis.com',
'wixpress.com', 'shopify.com', 'amazonaws.com', 'cloudflare.com',
];
function isValidEmail(email) {
const lower = email.toLowerCase();
if (SKIP_DOMAINS.some(d => lower.endsWith('@' + d))) return false;
if (/\.(png|jpg|svg|css|js)$/i.test(lower)) return false;
if (/^(noreply|no-reply|donotreply|postmaster)/i.test(lower.split('@')[0])) return false;
return true;
}
Typical email hit rate: 40-60% of businesses have a public email on their website.
Option A: Build It Yourself (n8n + Playwright)
If you're self-hosting n8n on a VPS, you can run the full pipeline yourself.
Node structure:
Manual Trigger / Schedule
→ Code: Build search URL
→ Playwright: Scrape Maps search results
→ Split In Batches (1 at a time)
→ Playwright: Extract place details
→ HTTP Request: Fetch business website
→ Code: Extract emails with regex
→ Google Sheets: Append row
The key Playwright snippet for collecting place links:
async function collectPlaceLinks(page, maxResults) {
const collected = new Set();
let noGrowthRounds = 0;
while (collected.size < maxResults) {
const links = await page.$$eval(
'a[href*="/maps/place/"]',
els => els.map(el => el.href)
);
links.forEach(l => collected.add(l));
// Scroll to load more
await page.evaluate(() => {
const feed = document.querySelector('div[role="feed"]');
if (feed) feed.scrollBy(0, 1200);
});
await page.waitForTimeout(1800);
// Stop if no new results after 3 scrolls
if (collected.size === prevSize) noGrowthRounds++;
if (noGrowthRounds >= 3) break;
}
return [...collected].slice(0, maxResults);
}
Memory warning: Don't run more than 1 concurrent browser instance. Google Maps detail pages are heavy. Process one place at a time (maxConcurrency: 1).
Option B: Use the Apify Actor (No Infrastructure Needed)
If you don't want to manage Playwright on your own infrastructure, the same pipeline is available as an Apify actor.
Apify handles the browser infrastructure, proxies, and scaling. You provide the search parameters and get back a structured dataset.
Input:
{
"query": "dentistas",
"location": "Madrid",
"maxResults": 50,
"extractEmails": true,
"language": "es"
}
Output (per business):
{
"name": "Clínica Dental López",
"address": "Calle Gran Vía 28, Madrid",
"phone": "+34 91 123 4567",
"website": "https://clinicadentallopez.es",
"rating": 4.7,
"reviewCount": 183,
"category": "Dentist",
"hours": "Mon-Fri 9:00-20:00",
"emails": ["info@clinicadentallopez.es"],
"mapsUrl": "https://www.google.com/maps/place/..."
}
Pricing: $0.002 per result (pay-per-use, no subscription). 50 leads = $0.10.
The actor is Google Maps Business Enricher on Apify Store.
The Google Sheets Output
The pipeline writes directly to a Google Sheet with these columns:
Name | Address | Phone | Website | Rating | Reviews | Category | Hours | Emails | Maps URL | Extracted At
From there you can:
- Filter by rating to only target well-reviewed businesses
- Filter by email presence for immediate outreach
- Sort by review count to find established businesses (not fly-by-night)
- Export to CSV for your email tool
Use Cases
Agency prospecting: "Marketing agencies" + city → cold email pitch
B2B sales: "Clinics" + region → pitch your SaaS
Market research: Count how many businesses in a category exist in a city
Competitor mapping: Find all competitors in your area with their ratings
Supplier discovery: Find local suppliers in a specific category
Legal Considerations
This scrapes publicly available information from Google Maps and business websites — the same data you'd see if you searched manually. Treat the output like any other public directory data:
- Don't use it for spam
- Respect GDPR/CAN-SPAM — include unsubscribe options in any outreach
- Only contact businesses that are relevant to your offer
Get the Ready-Made Workflow
The n8n workflow version (for self-hosted setups) is available at n8nmarkets.com. Search "Google Maps Local Service Leads".
The Apify actor (no infrastructure needed, pay-per-result) is at apify.com/agoradelmediterraneo/google-maps-business-enricher.
What niche are you targeting for outreach? Curious to hear what verticals people are using this type of data for.
Top comments (0)