DEV Community

AgoraIntelligence
AgoraIntelligence

Posted on

Extract Business Leads from Google Maps with Emails — Automated Pipeline with n8n and Apify

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):

  1. Homepage
  2. /contact or /contacto
  3. /about or /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;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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/..."
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)