SerpAPI + Google Sheets, clean Google Maps leads
Scraping Google Maps leads manually looks simple until you’ve done it for an hour. Then it turns into tabs everywhere, copy-paste mistakes, and a “list” you don’t fully trust.
This is the kind of mess agency owners feel during outreach pushes, and marketers building local campaigns run into constantly. Even a small business owner trying to line up partnerships can use this Maps leads automation to build a clean list with fewer duplicates and actual contact paths.
You’ll see how the workflow pulls Google Maps results with SerpAPI, stores them in Google Sheets, and then finds generic emails (like contact@) using EmailListVerify so your outreach can start sooner.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: SerpAPI + Google Sheets, clean Google Maps leads
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/code.svg' width='40' height='40' /></div><br/>Extract next start value"]
n2["<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/>Merge all values from SERPAPI"]
n3["<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/>Transform data in the right .."]
n4@{ icon: "mdi:database", form: "rounded", label: "Add rows in Google Sheets", 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/httprequest.dark.svg' width='40' height='40' /></div><br/>SERPAPI - Scrape Google Maps.."]
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/itemLists.svg' width='40' height='40' /></div><br/>Remove duplicate items"]
n7["<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/itemLists.svg' width='40' height='40' /></div><br/>Split out items"]
n8@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Remove empty values", pos: "b", h: 48 }
n9@{ icon: "mdi:database", form: "rounded", label: "Google Sheets - Get searches..", pos: "b", h: 48 }
n10@{ icon: "mdi:swap-vertical", form: "rounded", label: "Extract keyword and location..", pos: "b", h: 48 }
n11@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Continue IF Loop is complete", pos: "b", h: 48 }
n12@{ icon: "mdi:play-circle", form: "rounded", label: "Run workflow once a week", pos: "b", h: 48 }
n13@{ icon: "mdi:database", form: "rounded", label: "Save google map data to goog..", pos: "b", h: 48 }
n14@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Check if the listing has a w..", 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/code.svg' width='40' height='40' /></div><br/>Transform website into domai.."]
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/>Use EmailListVerify API to f.."]
n7 --> n8
n8 --> n3
n6 --> n13
n1 --> n11
n12 --> n9
n11 --> n5
n11 --> n2
n2 --> n7
n5 --> n1
n0 --> n9
n14 --> n15
n3 --> n6
n15 --> n16
n13 --> n14
n10 --> n5
n9 --> n10
n16 --> n4
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,n12 trigger
class n8,n11,n14 decision
class n4,n9,n13 database
class n5,n16 api
class n1,n2,n3,n15 code
classDef customIcon fill:none,stroke:none
class n1,n2,n3,n5,n6,n7,n15,n16 customIcon
The Problem: Google Maps leads are messy to collect
Google Maps is full of great local business leads, but getting that data into a usable outreach list is the painful part. You search, open listings, copy names, grab phone numbers, hunt for websites, then repeat. And after all that work, you still end up with duplicates, missing fields, and rows that can’t be contacted because there’s no email. The worst part is the uncertainty. You don’t know if your list is complete, and you don’t want to waste a day emailing dead ends.
It adds up fast. Here’s where it breaks down in the real world.
- Copying 30–50 listings into a spreadsheet takes a couple hours, and it’s easy to paste a phone number into the wrong row.
- Duplicates creep in when you run multiple searches across nearby cities, which means you message the same business twice.
- Most teams don’t have a consistent way to track offsets and pagination, so results silently stop before you hit the real volume.
- Even with a clean list, finding a contact email is another round of tab-hopping that kills momentum.
The Solution: SerpAPI → Sheets → email discovery, automatically
This workflow takes a simple input (your Google Maps search queries in a Google Sheet) and turns it into an outreach-ready lead list. It starts on a schedule or via a manual run, loads your search inputs, and sends them to SerpAPI to scrape Google Maps results. Those results get cleaned up into a consistent format, filtered so empty records don’t pollute your data, and deduplicated so you’re not chasing the same place twice. Next, the workflow stores the cleaned “places” in a sheet, checks whether each place has a website, and extracts the domain when it does. Finally, it calls EmailListVerify to discover a generic contact email and appends those email rows back into Google Sheets.
The workflow begins with your saved searches in Google Sheets. SerpAPI pulls listings from Google Maps and n8n handles pagination so you keep collecting results instead of stopping early. After deduping and website checks, EmailListVerify fills in contact emails and everything lands back in Sheets for outreach.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you target 3 cities and 2 categories (like “restaurants” and “hotels”), so you run 6 Google Maps searches each week and collect about 30 leads per search. Doing it manually, you might spend roughly 2 minutes per lead copying details and checking for a site, which is about 6 hours for 180 leads. With this workflow, you update the search inputs in Google Sheets (maybe 10 minutes), let SerpAPI fetch results, and then EmailListVerify fills in generic emails automatically. You still review the sheet, but you’re reviewing data, not building it from scratch.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Google Sheets to store searches and lead output
- SerpAPI for scraping Google Maps results
- EmailListVerify API key (get it from your EmailListVerify dashboard)
Skill level: Intermediate. You’ll connect accounts, add API keys, and confirm sheet columns match what the workflow expects.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
Your search list triggers the run. The workflow starts either on a weekly schedule or when you click a manual run. It immediately loads your prepared search inputs from Google Sheets.
SerpAPI pulls Google Maps results. n8n builds the query parameters, sends the request through an HTTP call, then aggregates results across pages using an offset loop so you don’t stop at the first page.
Results are cleaned and deduplicated. It expands the items, filters out empty records, normalizes fields into a consistent shape, and removes duplicates before storing the “places” in your sheet.
Email discovery runs only where it makes sense. If a listing has a website, the workflow extracts the domain and sends it to EmailListVerify. The discovered email rows are appended back into Google Sheets so outreach can start.
You can easily modify the Google Sheets input columns to match your own naming, or swap the schedule timing based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Manual & Schedule Triggers
Set up how the workflow starts, either manually for testing or on a weekly schedule for production runs.
- Open Manual Run Trigger to allow on-demand runs during setup and testing.
- Open Weekly Schedule Start and set the rule interval to
weeksto run on a weekly cadence. - Confirm both triggers connect to Load Search Inputs to keep the entry point consistent for manual and scheduled runs.
Step 2: Connect Google Sheets for Input & Storage
Load search URLs and store results in Google Sheets.
- In Load Search Inputs, set Document to
https://docs.google.com/spreadsheets/d/[YOUR_ID]/edit#gid=[YOUR_ID]and choose the sheetAdd your search url here. Credential Required: Connect yourgoogleSheetsOAuth2Apicredentials. - In Store Places Sheet, set Operation to
appendOrUpdate, choose sheetResults, and ensure the columns map to expressions like{{ $json.title }}and{{ $json.place_id }}. Credential Required: Connect yourgoogleSheetsOAuth2Apicredentials. - In Append Email Rows, set Operation to
appendOrUpdate, choose sheetEmails, and keep the column mapping expressions such as{{ $json.email }}and{{ $json.domain }}. Credential Required: Connect yourgoogleSheetsOAuth2Apicredentials.
Step 3: Set Up URL Parsing & Search Query Preparation
Transform input URLs into keyword and geo parameters for the API query.
- In Parse URL Parameters, set keyword to
{{ $json.URL.match(/\/search\/(.*?)\//)[1] }}. - In Parse URL Parameters, set geo to
{{ $json.URL.match(/(@[^\?\/]+)/)[1]}}. - Verify Load Search Inputs outputs into Parse URL Parameters, and then into Google Maps API Query.
Step 4: Configure the Google Maps API Pagination Loop
Use SerpApi to fetch multiple pages of results and aggregate them.
- In Google Maps API Query, set URL to
https://serpapi.com/search.jsonand enable Send Query with parameters:engine=google_maps,q={{$json?.search_parameters?.q || $json.keyword }},ll={{ $json?.search_parameters?.ll|| $json.geo }},type=search,start={{ $json.start|| 0 }}. Credential Required: Connect yourserpApicredentials. - In Derive Next Offset, keep the JS that extracts
startfromserpapi_pagination.nextto power pagination. - In Pagination Loop Check, ensure the conditions check
{{ $json.search_parameters.start }}and{{ $json.serpapi_pagination.next }}are not empty, sending true results back to Google Maps API Query and false results to Aggregate Serp Results. - In Aggregate Serp Results, keep the JS code that collects all
local_resultsfrom Google Maps API Query.
Step 5: Clean, Normalize, and Store Places Data
Expand the aggregated results, remove empty records, normalize data, and deduplicate places before storing them.
- In Expand Result Items, set Field to Split Out to
allData. - In Filter Empty Records, set the condition Value 1 to
{{ $json[0] }}with OperationisNotEmpty. - In Normalize Data Shape, keep the JS code that merges items into a single array and filters nulls.
- In Deduplicate Places, set Operation to
removeDuplicateswith Fields to Compare set toplace_id. - Confirm the sequence follows: Aggregate Serp Results → Expand Result Items → Filter Empty Records → Normalize Data Shape → Deduplicate Places → Store Places Sheet.
Step 6: Configure Email Lookup and Append Results
Extract the website domain, request contact emails, and append verified emails to the output sheet.
- In Validate Website Exists, keep the condition
{{ $json.website }}not starting with[undefined]to filter valid websites. - In Extract Domain Name, keep the JS that parses the domain and removes
www.if present. - In Email Lookup Request, set URL to
https://api.emaillistverify.com/api/findContact, Method toPOST, and JSON Body to{ "domain": "{{ $json.domain }}" }. Credential Required: Connect yourhttpHeaderAuthcredentials. - Ensure the flow continues from Email Lookup Request to Append Email Rows.
website field for each place.Step 7: Test and Activate Your Workflow
Run a manual test to verify the workflow pulls data, deduplicates it, and appends email results to the Sheets.
- Click Manual Run Trigger to start a test execution.
- Confirm that Store Places Sheet writes rows to the
Resultssheet and Append Email Rows writes to theEmailssheet. - Check that Pagination Loop Check ends at Aggregate Serp Results when no further pagination exists.
- When satisfied, toggle the workflow to Active so Weekly Schedule Start runs automatically.
Common Gotchas
- Google Sheets credentials can expire or need specific permissions. If things break, check the n8n credential connection status 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.
- SerpAPI requests can quietly fail when parameters change or you hit plan limits. If your output sheet suddenly looks thin, review the SerpAPI response inside the HTTP Request node and confirm you’re still under your monthly search quota.
Frequently Asked Questions
About 30 minutes if your Sheets and API keys are ready.
No. You’ll mostly connect accounts and paste in API keys. The only “technical” part is making sure your Google Sheet columns match the workflow’s expectations.
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 SerpAPI limits (250 searches/month on the free plan) and EmailListVerify costs (from about $0.05 per email).
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 Google Sheets change. Add more rows to your “search inputs” sheet (different categories, cities, or radius terms), and the workflow will loop through them during the scheduled run. If you want separate output tabs per category, you can duplicate the “Store Places Sheet” / “Append Email Rows” logic and route based on the query field.
Usually it’s permissions. Reconnect the Google Sheets credential in n8n, then confirm the specific spreadsheet is shared with the connected Google account. Also check that the sheet name and tab names still match what the workflow references, because renaming a tab can break writes instantly.
On n8n Cloud Starter, you can run a healthy amount of weekly scraping for small campaigns, but the real cap is your SerpAPI plan and how many searches you run. If you self-host, there’s no execution limit from n8n itself, so scaling is mostly about API quotas and your server size. In practice, most teams start with a few hundred leads per week, then widen searches once they trust the output.
Often, yes. This workflow relies on looping, pagination, deduplication, and conditional checks (like “does a website exist?”), which n8n handles cleanly without turning every extra branch into a cost decision. Self-hosting is also a big deal if you plan to scale scraping runs. Zapier or Make can be simpler for a tiny two-step flow, but they get clunky once you’re managing batches of results and normalizing data. If you want help picking the right setup for your outreach volume, Talk to an automation expert.
You end up with a lead sheet you can actually use, not one you have to babysit. Set it up once, run it weekly, and keep your outreach moving.
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.