DEV Community

Perufitlife
Perufitlife

Posted on

Build a Lead-Gen Automation in n8n: Scrape, Enrich, Export

Most "lead generation" tutorials stop at scraping a list of business names. But a name and a phone number isn't a lead - a name, a decision-maker email, and a verified contact channel is. In this tutorial we'll build a complete lead-gen pipeline in n8n that does all three stages: scrape businesses from Google Maps, enrich them with emails crawled straight off their websites, and export a clean list to Google Sheets.

No code, no scraper maintenance. We lean on n8n's generic Apify node to run two ready-made actors and chain them together.

The pipeline at a glance

Trigger -> Scrape (Google Maps) -> Enrich (Website Contact Finder) -> Export (Sheets)
Enter fullscreen mode Exit fullscreen mode
  1. Scrape - pull businesses for a niche + city from Google Maps (name, phone, website, rating).
  2. Enrich - take each business website and crawl it for emails, phones, and social links.
  3. Export - write the merged record to Google Sheets as one row per lead.

Stage 1 gives you reach. Stage 2 gives you the email that actually makes the lead actionable.

Prerequisites

  • A running n8n instance (cloud or self-hosted).
  • A free Apify account. Grab your Personal API token from Settings -> Integrations.

That's it. Both actors we use are on the Apify Store and run through the same generic Apify node, so you only configure one credential.

Step 1 - Add the Apify credential

Add a node in n8n, search Apify, choose the generic Apify node. When it asks for credentials, select Apify API and paste your token. Save. You'll reuse this credential for both the scrape and enrich steps.

Step 2 - Scrape businesses from Google Maps

Add your first Apify node. Configure it to run the Google Maps Email Extractor actor (renzomacar/google-maps-businesses):

  • Operation: Run actor and get dataset
  • Actor: renzomacar/google-maps-businesses
  • Input (JSON):
{
  "searchQueries": [
    "marketing agencies in Denver CO"
  ],
  "maxResultsPerQuery": 50,
  "language": "en",
  "includeWebsite": false
}
Enter fullscreen mode Exit fullscreen mode

Notice includeWebsite is false here. We deliberately keep this stage fast and cheap - we just want the business list and their website URLs. The deep email crawl happens in the next step with a dedicated tool that does it better.

Each output item looks like:

{
  "name": "Summit Digital",
  "phone": "+1 720-555-0142",
  "website": "https://summitdigital.co",
  "rating": 4.8,
  "reviewsCount": 96
}
Enter fullscreen mode Exit fullscreen mode

Step 3 - Enrich each business with emails

Now the enrichment step. Add a second Apify node, this time running the Email & Contact Finder actor (renzomacar/website-contact-finder). This actor crawls a website's contact, about, and team pages and extracts emails, phone numbers, social profiles, and even the tech stack.

The trick is feeding it the website URLs from Step 2. The actor takes a domains array, so collect the websites from the previous node and pass them in. A simple way: drop a Code node between the two Apify nodes to gather the URLs.

// Code node: collect website URLs from the Google Maps results
const domains = items
  .map(i => i.json.website)
  .filter(Boolean);

return [{ json: { domains } }];
Enter fullscreen mode Exit fullscreen mode

Then configure the second Apify node:

  • Operation: Run actor and get dataset
  • Actor: renzomacar/website-contact-finder
  • Input (JSON):
{
  "domains": {{ $json.domains }},
  "maxPagesPerDomain": 4,
  "includeGenericEmails": true,
  "detectTechStack": true
}
Enter fullscreen mode Exit fullscreen mode

The domains value is mapped from the Code node, so it scales automatically with however many businesses you scraped. Each enriched result comes back like:

{
  "domain": "summitdigital.co",
  "emails": ["hello@summitdigital.co", "jobs@summitdigital.co"],
  "phones": ["+1 720-555-0142"],
  "socialLinks": {
    "linkedin": "https://linkedin.com/company/summit-digital",
    "instagram": "https://instagram.com/summitdigital"
  },
  "techStack": ["WordPress", "HubSpot"]
}
Enter fullscreen mode Exit fullscreen mode

Now you have an email and a social channel for outreach - the difference between a raw list and a usable pipeline. Bonus: the detected tech stack lets you segment ("everyone on HubSpot," "everyone still on WordPress") for sharper messaging.

Step 4 - Merge and export to Google Sheets

You've got two datasets: businesses (Step 2) and contacts (Step 3). Use n8n's Merge node set to Combine -> Merge By Key, keying on the website/domain so each business lines up with its scraped emails. Then add a Google Sheets node with operation Append Row and map the columns:

Sheet column Expression
Business {{ $json.name }}
Email {{ $json.emails[0] }}
Phone {{ $json.phone }}
Website {{ $json.website }}
LinkedIn {{ $json.socialLinks.linkedin }}
Tech {{ $json.techStack.join(", ") }}

Run it. Each row is now a real, enriched, ready-to-contact lead.

Step 5 - Put it on a schedule

Swap the manual trigger for a Schedule Trigger and rotate your searchQueries across cities and niches. Every run adds fresh, enriched leads to the sheet with no manual effort. Add a dedupe step (key on email or domain) if you run overlapping searches.

Why split scrape and enrich into two actors?

You could ask the Google Maps actor to visit websites itself (includeWebsite: true) and call it a day. That's fine for small jobs. But splitting the stages gives you two wins: the scrape stays fast and cheap, and the enrichment is far more thorough - the contact-finder actor crawls multiple pages per domain (contact, about, team) rather than just the homepage, so it surfaces emails the quick pass misses. For serious outreach lists, the two-stage pipeline pulls noticeably more verified emails.

Wrap-up

That's a full lead-gen machine in n8n with zero scraping code:

Both actors run through the same generic Apify node, so once your token is in, you can recombine them into any pipeline you like - reviews monitoring, competitor research, recruiting, you name it.

Now go fill that sheet.

Top comments (0)