Google Maps to Google Sheets, enriched leads ready
Copying leads out of Google Maps is already annoying. The worst part is what comes after: broken emails, missing websites, and a sheet full of “maybe” contacts you don’t trust enough to message.
Google Maps leads automation fixes that mess for marketing managers who need lists they can actually use, founders trying to keep pipeline moving, and agencies who can’t afford sloppy data. You end up with enriched rows, validated emails, and outreach drafts that don’t sound like a template from 2012.
This workflow pulls businesses from Google Maps, cleans and enriches the records, then writes everything to Google Sheets (including AI-personalized outreach). You’ll see how the pieces fit, what you need, and where teams usually get stuck.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Google Maps to Google Sheets, enriched leads ready
flowchart LR
subgraph sg0["When clicking ‘Execute workflow’ Flow"]
direction LR
n0@{ icon: "mdi:play-circle", form: "rounded", label: "When clicking ‘Execute workf..", pos: "b", h: 48 }
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>HTTP Request"]
n2@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields2", pos: "b", h: 48 }
n3@{ icon: "mdi:swap-vertical", form: "rounded", label: "Loop Over Items", pos: "b", h: 48 }
n4@{ icon: "mdi:robot", form: "rounded", label: "AI Agent", pos: "b", h: 48 }
n5@{ icon: "mdi:database", form: "rounded", label: "Append or update row in sheet3", pos: "b", h: 48 }
n6["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Code"]
n7@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Filter3", pos: "b", h: 48 }
n8@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Filter5", pos: "b", h: 48 }
n9@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields", pos: "b", h: 48 }
n10@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model", pos: "b", h: 48 }
n11@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Filter", pos: "b", h: 48 }
n12@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields1", pos: "b", h: 48 }
n13@{ icon: "mdi:database", form: "rounded", label: "Append or update row in sheet", pos: "b", h: 48 }
n6 --> n3
n11 --> n12
n7 --> n2
n8 --> n6
n4 --> n5
n9 --> n4
n12 --> n13
n2 --> n8
n1 --> n7
n1 --> n11
n3 --> n9
n10 -.-> n4
n5 --> n3
n0 --> n1
end
subgraph sg1["Google Sheets Flow"]
direction LR
n14@{ icon: "mdi:swap-vertical", form: "rounded", label: "Batch Processing Logic", pos: "b", h: 48 }
n15["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Scrape Website Content"]
n16["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Extract Contact Information"]
n17@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Filter6", pos: "b", h: 48 }
n18@{ icon: "mdi:play-circle", form: "rounded", label: "Google Sheets Trigger", pos: "b", h: 48 }
n19@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields3", pos: "b", h: 48 }
n20@{ icon: "mdi:database", form: "rounded", label: "Append or update row in sheet1", pos: "b", h: 48 }
n17 --> n14
n19 --> n15
n18 --> n17
n14 --> n19
n15 --> n16
n16 --> n20
n20 --> n14
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n0,n18 trigger
class n4 ai
class n10 aiModel
class n7,n8,n11,n17 decision
class n5,n13,n20 database
class n1,n15 api
class n6,n16 code
classDef customIcon fill:none,stroke:none
class n1,n6,n15,n16 customIcon
The Problem: Google Maps leads are messy in the real world
On paper, “scrape Google Maps leads and upload to a sheet” sounds simple. In practice, it’s a time sink with a second hidden cost: you don’t know which rows are safe to contact. Some businesses have no email listed. Some have a website, but the contact page is buried or the domain is dead. And even when you find an email, you still have to write a message that looks like you did ten seconds of homework. That’s how lead gen becomes tab hopping, spreadsheet triage, and half-finished outreach.
It adds up fast. Here’s where it breaks down.
- Pulling leads manually from Google Maps and websites can eat about 2 hours for every 50 businesses you research.
- Enrichment is inconsistent, so you end up with a sheet full of missing emails, missing socials, and “call the number” as the only option.
- Bad emails slip into outreach, which means bounces, wasted sending limits, and a reputation hit you don’t notice until replies dry up.
- Even with a decent list, writing personalized first touches is slow, and generic outreach gets ignored.
The Solution: Google Maps leads → enriched rows + outreach drafts in Sheets
This workflow turns Google Maps results into a working lead list inside Google Sheets, with enrichment and outreach handled for you. It starts with an API request to collect businesses based on your search (location, keyword, category). Each lead is transformed into a consistent format, then processed in batches so you can handle bigger pulls without babysitting the run. Leads that already include contact details and social profiles get mapped, filtered, and email-checked before they’re used. Leads that are missing enrichment don’t get thrown away; they’re sent to a separate Google Sheet where a second workflow picks them up, crawls the business website, and extracts whatever extra contact info it can find. Finally, AI nodes generate tailored outreach content and the workflow writes the results back to your sheet.
The workflow kicks off when you run it manually (or when your AI agent calls the MCP endpoint). From there, it enriches what it can via the scraper, validates emails, and writes ready-to-use leads into Google Sheets. Any “incomplete” rows get a second pass via website crawling, then you receive updated enrichment plus personalized outreach drafts.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you need 100 local leads for a niche campaign. Doing it manually usually means checking Google Maps, opening websites, hunting for emails/socials, then writing rows into a sheet; call it about 3 minutes per business, so roughly 5 hours. With this workflow, you run one search, then let batch enrichment and website crawling fill the gaps while you do something else. You still review the sheet at the end, but that’s more like 20 minutes of QA instead of an afternoon of busywork.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Google Sheets for storing enriched leads and drafts
- Apify to scrape and enrich Google Maps results
- Firecrawl for crawling business websites for missing info
- OpenAI API key (get it from the OpenAI dashboard)
Skill level: Intermediate. You’ll connect a few accounts, paste API keys, and be comfortable testing runs in n8n.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
A lead search triggers the run. You start the workflow with a manual launch (or via an MCP-compatible call), passing search inputs like location and category so the external request can pull Google Maps leads.
Leads get normalized and processed in batches. n8n transforms raw responses into consistent fields (name, website, phone, categories, and enrichment fields), then loops through them in split batches so you can run larger lists without everything timing out.
Enrichment, filtering, and outreach drafting happen in the middle. Enriched leads are mapped and filtered, emails are validated, and an AI agent drafts outreach using the lead’s details (and any available context). Rows that are missing enrichment are written to a separate Google Sheet for follow-up crawling.
A second pass fills the gaps via website crawling. A Google Sheets trigger monitors the “missing enrichment” sheet, checks if a website exists, crawls it through Firecrawl, and uses code nodes to extract socials or contact info before updating the sheet.
You can easily modify the enrichment rules to match your ICP (for example, require a website, or only accept certain categories) based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Manual Trigger
Start the workflow manually so you can validate the API pull and downstream logic before enabling any scheduled or sheet-based triggers.
- Add and position Manual Launch Trigger as the starting node.
- Connect Manual Launch Trigger to External API Request.
title, leadsEnrichment, and website before wiring downstream mappings.Step 2: Connect External API and Route Leads in Parallel
This workflow pulls raw leads from Apify and immediately splits into two parallel paths for enriched and unenriched data.
- Open External API Request and set URL to
https://api.apify.com/v2/acts/:actorId/run-sync-get-dataset-itemsand Method toPOST. - Under Headers, set Accept to
application/jsonand Authorization toBearer [CONFIGURE_YOUR_TOKEN]. - Confirm Send Body and Send Headers are enabled, and Body Content Type is
JSON. - Ensure External API Request outputs to both Filter Enriched Leads and Filter Unenriched Leads in parallel.
Bearer [CONFIGURE_YOUR_TOKEN] or the request will fail.Step 3: Process Lead Records and Validate Emails
Enriched leads flow through field mapping, email validation, record transformation, and batching to feed the AI composer.
- In Filter Enriched Leads, keep the condition that
{{$json.leadsEnrichment}}is not empty. - In Map Lead Fields, map key fields using expressions like
{{$json.title}},{{$json.leadsEnrichment[0].email}}, and{{$json.website}}. - In Validate Lead Emails, keep the OR rules for
{{$json["leadsEnrichment[0].email"]}}and{{$json["leadsEnrichment[2].email"]}}being not empty. - In Transform Lead Records, keep the JavaScript for flattening
leadsEnrichmentinto individual contacts. - Ensure Transform Lead Records connects to Iterate Lead Batches, which outputs to Prepare AI Inputs on its second output.
leadsEnrichment entries, adjust the email validation rules to avoid false negatives.Step 4: Configure AI Outreach Generation
Prepare inputs, generate a personalized paragraph, and send the result to Google Sheets.
- In Prepare AI Inputs, map fields using expressions like
{{$json.fullName}},{{$json.jobTitle}},{{$json.email}}, and{{$json.website}}. - Open AI Outreach Composer and keep the prompt body, including expressions like
{{ $('Prepare AI Inputs').item.json.fullName }}and{{ $('Prepare AI Inputs').item.json.jobTitle }}. - Ensure OpenAI Chat Engine is connected as the language model for AI Outreach Composer, and set the model to
gpt-4.1-mini. - In Update Outreach Sheet, confirm Operation is
appendOrUpdateand the column mappings use expressions like{{$('Prepare AI Inputs').item.json.fullName}}and{{$json.output}}.
Credential Required: Connect your openAiApi credentials in OpenAI Chat Engine.
Credential Required: Connect your googleSheetsOAuth2Api credentials in Update Outreach Sheet.
Step 5: Store Unenriched Leads in Google Sheets
Unenriched leads are logged separately so you can review and enrich them later.
- In Filter Unenriched Leads, keep the condition that
{{$json.leadsEnrichment}}is empty. - In Map Basic Lead Data, map fields like
{{$json.title}},{{$json.street}}, and{{$json.website}}. - In Update Unenriched Sheet, set Operation to
appendOrUpdateand map the Title column for matching.
Credential Required: Connect your googleSheetsOAuth2Api credentials in Update Unenriched Sheet.
Step 6: Scrape Websites and Extract Social Profiles
This branch listens for sheet updates, scrapes the website, extracts social links, and writes them back to a social sheet.
- Configure Sheet Update Trigger to watch the same spreadsheet, and keep the polling mode at
everyMinute. - In Check Website Exists, ensure the condition checks
{{$json.Website}}is not empty. - In Batch Cycle Handler, keep the batch output to Map Website Fields on output index 1.
- In Map Website Fields, map fields like
{{$json.Title}}and{{$json.Website}}. - In Scrape Site Content, set URL to
https://api.firecrawl.dev/v1/scrapeand JSON Body to{"url":"{{ $json.Website }}","formats":["markdown","html"]}. - In Extract Social Profiles, keep the JavaScript that parses social profile URLs.
- In Update Social Sheet, keep Operation as
appendOrUpdateand map columns using expressions like{{$('Map Website Fields').item.json.Title}}and{{$json.facebook[0]}}.
Credential Required: Connect your googleSheetsTriggerOAuth2Api credentials in Sheet Update Trigger.
Credential Required: Connect your googleSheetsOAuth2Api credentials in Update Social Sheet.
Bearer [CONFIGURE_YOUR_TOKEN] with your Firecrawl token.Step 7: Test and Activate Your Workflow
Run a full manual test to verify API ingestion, enrichment logic, AI output, and sheet updates.
- Click Execute Workflow starting from Manual Launch Trigger and confirm data reaches Update Outreach Sheet with a filled
Peronalized startersfield. - Verify that unenriched leads appear in the sheet configured in Update Unenriched Sheet when
leadsEnrichmentis empty. - Trigger a test row update in the sheet monitored by Sheet Update Trigger and confirm social links are written by Update Social Sheet.
- When results look correct, activate the workflow using the Active toggle in the n8n editor.
Common Gotchas
- Google Sheets credentials can expire or need specific permissions. If things break, check the n8n credential connection test and the target spreadsheet sharing settings first.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Default prompts in AI nodes are generic. Add your brand voice early or you’ll be editing outputs forever.
Frequently Asked Questions
About 45 minutes if your accounts and sheets are ready.
No. You’ll mostly connect credentials and adjust a few mapping fields in n8n.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in OpenAI API costs (often a few dollars a month for typical lead volumes) plus whatever Apify and Firecrawl usage you run.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, and you should, honestly. Most teams tweak the field mapping (“Map Lead Fields” and “Prepare AI Inputs”) and adjust the AI agent prompt so the outreach matches their offer and tone. You can also tighten the filters to only keep leads with a website or only keep categories you actually sell to. If you want different enrichment sources, swap the HTTP request and code extraction pieces that handle crawling and parsing.
Usually it’s expired Google authorization or the sheet isn’t shared with the right Google account. Reconnect the Google Sheets credential in n8n and confirm the spreadsheet and worksheet names still match what the nodes expect. If it fails only on updates, check that the workflow is writing to a tab that exists and that your account has edit access, not view-only.
Hundreds per run is normal if you process them in batches, but the practical limit depends on your n8n plan and your Apify/Firecrawl quotas.
Often, yes, because this workflow isn’t just “move rows around.” You’re batching, filtering enriched vs. unenriched leads, validating emails, then running a second workflow off a Google Sheets trigger to crawl websites and extract socials. That kind of multi-pass logic gets awkward (and pricey) in Zapier, and Make scenarios can get brittle once you add retries and branching. n8n also gives you the option to self-host, which matters when you start doing bigger lead pulls. If your use case is only “scrape → put into a sheet,” simpler tools might be fine. Talk to an automation expert if you want a quick recommendation for your exact stack.
Once this is running, your lead list stops being a “research project” and starts being a weekly habit. The workflow handles the repetitive stuff, so you can spend your time on targeting and follow-up.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.