Google Maps to Google Sheets, clean leads on demand
Lead lists fall apart in the messy middle. You start with a good search, then it turns into tab overload, copy-paste errors, and “we’ll clean it later” data that never gets cleaned.
This is the kind of Google Maps leads automation that saves SDRs hours, but local marketing agency teams and solo consultants feel the relief too. Instead of building lists by hand, you can generate an enriched sheet on demand, with duplicates removed before they waste your time.
Below, you’ll see how the workflow pulls businesses from Google Search and Google Maps, scrapes contact details from their sites, and logs clean rows to Google Sheets so you can start outreach the same day.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Google Maps to Google Sheets, clean leads on demand
flowchart LR
subgraph sg0["When chat message received Flow"]
direction LR
n0@{ icon: "mdi:play-circle", form: "rounded", label: "When chat message received", pos: "b", h: 48 }
n1@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If", pos: "b", h: 48 }
n2@{ icon: "mdi:database", form: "rounded", label: "Append row in sheet", pos: "b", h: 48 }
n3@{ icon: "mdi:cog", form: "rounded", label: "Remove Duplicates", pos: "b", h: 48 }
n4@{ icon: "mdi:swap-vertical", form: "rounded", label: "Loop Over Items", pos: "b", h: 48 }
n5["<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 URLs"]
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/httprequest.dark.svg' width='40' height='40' /></div><br/>Scrape Google Maps"]
n7@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Filter Google URLs", pos: "b", h: 48 }
n8@{ icon: "mdi:cog", form: "rounded", label: "Wait2", pos: "b", h: 48 }
n9@{ icon: "mdi:database", form: "rounded", label: "Get row(s) in sheet", pos: "b", h: 48 }
n10@{ icon: "mdi:database", form: "rounded", label: "Get row(s) in sheet1", pos: "b", h: 48 }
n11@{ icon: "mdi:cog", form: "rounded", label: "Remove Duplicates3", pos: "b", h: 48 }
n12@{ icon: "mdi:database", form: "rounded", label: "Append row in sheet2", pos: "b", h: 48 }
n13@{ icon: "mdi:swap-vertical", form: "rounded", label: "Loop Over Items1", pos: "b", h: 48 }
n14["<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/>Setting Pagination"]
n15@{ icon: "mdi:swap-vertical", form: "rounded", label: "Loop for Multiple Page Search", pos: "b", h: 48 }
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/httprequest.dark.svg' width='40' height='40' /></div><br/>Custom Google Search API"]
n17["<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/>Flatten Output Items"]
n18["<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/>Information Extraction"]
n19@{ icon: "mdi:cog", form: "rounded", label: "Remove Duplicates From Searc..", pos: "b", h: 48 }
n20["<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 Site2"]
n21@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If Site scrapped", pos: "b", h: 48 }
n22["<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 Required Fields"]
n23@{ icon: "mdi:swap-vertical", form: "rounded", label: "Set All Fields", pos: "b", h: 48 }
n24@{ icon: "mdi:swap-vertical", form: "rounded", label: "Set URL for Validation", pos: "b", h: 48 }
n25["<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/merge.svg' width='40' height='40' /></div><br/>Not Duplicate Search Results"]
n26@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If Site Exists", pos: "b", h: 48 }
n27@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Exclude Articles and Blogs", pos: "b", h: 48 }
n28@{ icon: "mdi:cog", form: "rounded", label: "Remove Duplicates For Sheets", pos: "b", h: 48 }
n29@{ icon: "mdi:database", form: "rounded", label: "Add Search Results in Sheets", pos: "b", h: 48 }
n30["<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/>Prepare Query for Maps"]
n31["<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 Map Sites"]
n32["<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 Information"]
n33@{ icon: "mdi:swap-vertical", form: "rounded", label: "Set URL Validaiton", pos: "b", h: 48 }
n34["<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/merge.svg' width='40' height='40' /></div><br/>Validating Unique Results"]
n35@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If Site exists", pos: "b", h: 48 }
n1 --> n2
n1 --> n13
n8 --> n32
n5 --> n7
n20 --> n21
n26 --> n27
n35 --> n11
n23 --> n13
n4 --> n34
n4 --> n31
n21 --> n22
n21 --> n13
n13 --> n25
n13 --> n20
n31 --> n8
n3 --> n4
n7 --> n3
n11 --> n12
n6 --> n5
n33 --> n34
n14 --> n15
n32 --> n4
n9 --> n24
n17 --> n18
n10 --> n33
n18 --> n19
n30 --> n6
n24 --> n25
n22 --> n23
n16 --> n17
n34 --> n35
n27 --> n28
n0 --> n14
n0 --> n9
n0 --> n30
n0 --> n10
n25 --> n26
n28 --> n29
n15 --> n1
n15 --> n16
n19 --> n15
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 trigger
class n1,n7,n21,n26,n27,n35 decision
class n2,n9,n10,n12,n29 database
class n6,n16,n20,n31 api
class n5,n14,n17,n18,n22,n30,n32 code
classDef customIcon fill:none,stroke:none
class n5,n6,n14,n16,n17,n18,n20,n22,n25,n30,n31,n32,n34 customIcon
The Problem: Lead lists get dirty before you ever send the first email
If you’ve ever tried building a “quick” prospect list from Google, you already know the trap. The first 10 results look promising. Then you realize half the businesses are the same company showing up in different places, the other half have no visible email, and the phone numbers are inconsistent (site footer, contact page, a random directory listing). Now you’re doing detective work instead of outreach. And because the data is scattered, you can’t easily track what query created the lead, which means your next list pulls the same companies again.
The friction compounds. Here’s where it breaks down.
- Copying names, URLs, and phone numbers into a spreadsheet eats about 2 hours for a 100-lead list.
- Duplicates slip in from Google Maps and organic search overlap, so reps waste time “re-qualifying” the same business twice.
- Contact details are buried on the website, which forces manual clicking through menus, popups, and contact pages.
- List quality is inconsistent, so your outreach looks sloppy and reply rates drop for reasons you can’t diagnose quickly.
The Solution: Chat-driven scraping that writes clean leads to Google Sheets
This workflow turns lead generation into a simple request: you type a query into a chat interface (like “dentists in New York”), and n8n does the heavy lifting. It pulls results from two places at once: Google Search (through the Google Custom Search API) and Google Maps (via scraping). Then it collects each business website it finds, visits those sites, and extracts contact details from the page HTML. That’s where it gets practical: it looks for email addresses, phone numbers, and social links so you don’t have to hunt. Before anything lands in your spreadsheet, the workflow deduplicates leads and checks your existing Google Sheet, so you keep one clean row per business.
The workflow starts with your chat query, then loops through multiple search pages and maps results to build a combined lead pool. After that, it scrapes each website, extracts contact details, merges the results, and finally appends only unique rows to Google Sheets with the original search query for tracking.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you need 150 local leads for a new campaign. Manually, if you spend about 1 minute per lead to copy business name, URL, and phone, plus another minute clicking around for an email, that’s roughly 5 hours of fiddly work. With this workflow, you paste one query into the chat, let it collect results from Search and Maps, and wait for scraping to finish. You still review the sheet, but the “build the list” part becomes a quick check instead of a half-day project.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Google Sheets for storing the enriched lead list
- Google Custom Search API to pull Google Search results
- API key + Search Engine ID (cx) (get them from Google Cloud and Programmable Search Engine)
Skill level: Intermediate. You’ll mostly connect accounts and paste API credentials, but you should be comfortable testing runs and adjusting a few settings.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
You start with a chat query. A user types something like “roofers in Austin” into the workflow’s chat interface (powered by the n8n LangChain chat trigger). That message becomes the “job ticket” for the whole run.
Search and Maps results are collected in parallel. One branch builds a pagination list and calls the Google Custom Search API across multiple pages. Another branch formats a maps query, scrapes Google Maps, parses links, and filters them down to business websites.
Websites are scraped, then contact details are extracted. For each unique URL, the workflow fetches the HTML, checks that the scrape succeeded, and runs custom parsing to pull out emails, phone numbers, and social links. It also assembles consistent lead fields so the sheet stays tidy.
Duplicates are removed before writing to your sheet. The workflow fetches existing Google Sheets rows, checks whether the URL already exists, filters out content types that aren’t useful, and appends only clean, new leads along with the original search query.
You can easily modify the search query format to target different cities, niches, or keywords based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Chat Trigger
Set up the intake point so the workflow can accept a search query and start the lead capture process.
- Add the Chat Intake Trigger node as the trigger.
- Leave Options empty or customize if you want to restrict or format chat inputs.
- Note that Chat Intake Trigger outputs to four nodes in parallel: Build Pagination List, Fetch Sheet Rows, Format Maps Query, and Fetch Sheet Rows Alt.
{{$('Chat Intake Trigger').item.json.chatInput}} for search and logging.Step 2: Connect Google Sheets
These nodes read and append lead records to your spreadsheet. Configure the same document and sheet across all Google Sheets nodes.
- Open Fetch Sheet Rows and set Document to
[YOUR_ID]and Sheet Name togid=0. - Repeat the same document and sheet settings in Fetch Sheet Rows Alt.
- In Append Lead Row, ensure the column mappings match the expressions such as
{{$json.URL}},{{$json["Business Name"]}}, and{{$('Chat Intake Trigger').item.json.chatInput}}. - In Append Enriched Lead, confirm Type is set to
websiteand map fields like{{$json.businessName}}and{{$json.email1}}. - In Write Leads to Sheet, confirm mappings like
{{$json.URL}},{{$json.Name}}, and{{$json.Email1}}are aligned with your sheet columns.
Step 3: Set Up Pagination and Google Search Intake
This branch paginates through Google Custom Search API results and extracts core lead fields.
- In Build Pagination List, keep the JavaScript array of start indices as
[ 1, 11, 21, 31]. - Ensure Page Loop Handler splits batches from Build Pagination List and routes to Google Search Request.
- In Google Search Request, set the query parameters: key to
[CONFIGURE_YOUR_API_KEY], cx to[YOUR_ID], q to{{$('Chat Intake Trigger').item.json.chatInput}}, and start to{{$json.start}}. - Keep Flatten Search Items and Extract Search Fields as-is to transform API responses into lead records.
- Use Dedup Search Results to remove duplicates by setting Fields to Compare to
=URL.
[CONFIGURE_YOUR_API_KEY] or [YOUR_ID] in Google Search Request, the API call will fail. Replace them with your Custom Search credentials.Step 4: Configure Map Search and Filtering Pipeline
This branch scrapes Google Maps results, filters out irrelevant links, and prepares websites for scraping.
- In Format Maps Query, keep the script that builds
searchQueryby replacing spaces with+. - Set Maps Search Scraper URL to
=https://www.google.com/maps/search/{{$json.searchQuery}}. - In Parse Map Links, keep the regex logic that extracts URLs from
$input.first().json.data. - In Filter Map Links, keep the four notContains checks for
schema,google,gg, andgstaticusing{{$json.website}}. - Route through Eliminate Map Duplicates and Iterate Map URLs to batch processing for scraping.
Step 5: Scrape and Enrich Lead Data
This step scrapes websites, extracts contact details, and assembles enriched lead records.
- In Scrape Lead Site, keep URL as
{{$json.URL}}and Response Format as text for HTML parsing. - Use Scrape Success Check to validate
{{$json.data}}exists before extraction. - Keep Extract Contact Details as-is to parse emails, phones, and socials from HTML.
- In Assemble Lead Data, keep assignments like Name set to
{{$('Iterate Search Leads').item.json["Business Name"]}}and Email 2 to{{$json.email2}}. - In the Maps branch, keep Delay Throttle Amount set to
1to reduce rate-limiting risks. - Use Parse Map Contacts to extract business data from the HTML content returned by Scrape Map Websites.
Step 6: Apply Deduplication and Conditional Routing
Multiple checks and merges ensure only unique, valid leads move forward to your sheet.
- Use Merge Unique Search with Fields to Match set to
['URL']and Join Mode set tokeepNonMatches. - Set URL Exists Check to validate
{{$json.URL}}exists before content filtering. - Configure Filter Content Types to keep non-article content using the existing conditions on
{{$json.Type}}. - Run Dedup Before Sheet to remove duplicates before writing via Write Leads to Sheet.
- In the Maps path, use Merge Unique Maps and URL Exists Check 2 to validate unique URLs before Final Deduplication.
Step 7: Configure Output to Sheets
Two outputs write lead data: immediate search-derived records and enriched website-based records.
- In Write Leads to Sheet, confirm the mapping uses
{{$json.URL}},{{$json.Name}}, and{{$json.Email1}}. - In Append Enriched Lead, confirm the mapping uses
{{$json.businessName}},{{$json.email1}}, and{{$json.phone}}. - Use Append Lead Row to capture search results with email present; the flow is Email Present Check → Append Lead Row.
Step 8: Test and Activate Your Workflow
Validate each branch and confirm rows are appended to your Google Sheet before activating.
- Click Execute Workflow and provide a chat input (e.g., a business category and location) in Chat Intake Trigger.
- Verify that Chat Intake Trigger outputs to Build Pagination List, Fetch Sheet Rows, Format Maps Query, and Fetch Sheet Rows Alt in parallel.
- Check that Write Leads to Sheet and Append Enriched Lead add rows to your spreadsheet with populated fields.
- When successful, toggle the workflow to Active to run in production.
Common Gotchas
- Google Custom Search API credentials can expire or be restricted. If things break, check your Google Cloud API key and whether the Custom Search API is enabled in the project 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 30-60 minutes if your Google API access is ready.
No. You’ll connect Google accounts, paste API credentials, and test a few runs.
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 Google Custom Search API usage, which depends on your query volume.
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 it’s mostly a query change. Update the chat query format and, if needed, adjust the “Format Maps Query” code node so your Maps scrape targets the right location terms. You can also tweak the “Filter Content Types” if node to skip irrelevant URLs (like PDFs or directory pages). Common customizations include adding industry keywords, forcing a city/state pattern, and writing to a separate Google Sheet tab per campaign.
Usually it’s an expired Google OAuth connection in n8n or the spreadsheet permissions are wrong. Reconnect your Google Sheets credential in n8n, then confirm the exact Spreadsheet (Document ID) and Sheet Name still exist. If you recently duplicated a sheet, the workflow may still be pointing at the old file. Also check if your Google Workspace admin restricts API access, because that can block writes even when login “works.”
It depends mostly on your Google Custom Search API limits and how aggressive your batching/wait settings are. On n8n Cloud, the Starter plan supports a monthly execution cap (higher plans support more). If you self-host, there’s no execution limit, but your server and Google rate limits will still matter. In practice, many teams run batches of a few hundred leads per query to keep scraping stable and avoid timeouts.
For this exact job, n8n is usually the better fit because scraping, looping, deduping, and conditional logic get complicated fast. Zapier and Make can do parts of it, but you’ll often hit limits once you add pagination, batching, and website parsing. n8n also gives you self-hosting, which can matter when you’re running big prospecting pulls. If you just want “new row in sheet when a form is submitted,” keep it simple and use whatever you already pay for. Talk to an automation expert if you want help picking the cleanest route.
Once this is running, list building stops being a project. It becomes a quick request, a clean sheet, and a faster path to real conversations.
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.