This workflow corresponds to n8n.io template #16421 — we link there as the canonical source.
This workflow follows the Execute Workflow Trigger → Google Sheets recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "tKiKXqkcBMSEA3Ro",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Google Maps Email Scraper",
"tags": [
{
"id": "Ye83S67h8JUhrB7p",
"name": "\ud83d\udee0\ufe0f In progress",
"createdAt": "2026-06-16T12:55:35.976Z",
"updatedAt": "2026-06-16T12:55:35.976Z"
},
{
"id": "rB8MSKGhRY8lPoVX",
"name": "Secops",
"createdAt": "2026-06-16T12:55:36.001Z",
"updatedAt": "2026-06-16T12:55:36.001Z"
}
],
"nodes": [
{
"id": "695ef09a-5779-426e-b748-fb222932a319",
"name": "Remove Duplicate URLs",
"type": "n8n-nodes-base.removeDuplicates",
"position": [
-4000,
-624
],
"parameters": {},
"typeVersion": 1.1
},
{
"id": "2305475c-9277-43a0-b2ed-2d793095077d",
"name": "Loop over queries",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-4624,
-1312
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "98baa418-d482-466e-a5a3-16ed2bb39500",
"name": "Search Google Maps with query",
"type": "n8n-nodes-base.httpRequest",
"position": [
-4592,
-624
],
"parameters": {
"url": "=https://www.google.com/maps/search/{{ $json.query }}",
"options": {
"allowUnauthorizedCerts": false
}
},
"executeOnce": false,
"typeVersion": 4.2,
"alwaysOutputData": false
},
{
"id": "1ce6b969-519a-43e2-9831-246059076cfe",
"name": "Scrape URLs from results",
"type": "n8n-nodes-base.code",
"position": [
-4400,
-624
],
"parameters": {
"jsCode": "const data = $input.first().json.data\n\nconst regex = /https?:\\/\\/[^\\/]+/g\n\nconst urls = data.match(regex)\n\nreturn urls.map(url => ({json: {url: url}}))"
},
"typeVersion": 2
},
{
"id": "141294c1-1e21-4cd9-bb0b-fe1bcad6bf84",
"name": "Filter irrelevant URLs",
"type": "n8n-nodes-base.filter",
"position": [
-4192,
-624
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "041797f2-2fe2-41dc-902a-d34050b9b304",
"operator": {
"type": "string",
"operation": "notRegex"
},
"leftValue": "={{ $json.url }}",
"rightValue": "=(google|gstatic|ggpht|schema\\.org|example\\.com|sentry-next\\.wixpress\\.com|imli\\.com|sentry\\.wixpress\\.com|ingest\\.sentry\\.io)"
},
{
"id": "eb499a7e-17bc-453c-be08-a47286f726dd",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "734547ec-7fc0-4c83-841c-912e391f3466",
"name": "Request web page for URL",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
-3472,
-624
],
"parameters": {
"url": "={{ $json.url }}",
"options": {}
},
"typeVersion": 4.2,
"alwaysOutputData": false
},
{
"id": "5efd93b7-4309-4981-bbdc-7bd046e1a04c",
"name": "Loop over URLs",
"type": "n8n-nodes-base.splitInBatches",
"onError": "continueErrorOutput",
"position": [
-3760,
-640
],
"parameters": {
"options": {
"reset": false
}
},
"typeVersion": 3
},
{
"id": "0a8be2a4-afad-4efc-9fa1-06a137ddf4e1",
"name": "Loop over pages",
"type": "n8n-nodes-base.splitInBatches",
"onError": "continueErrorOutput",
"position": [
-3232,
-800
],
"parameters": {
"options": {}
},
"typeVersion": 3,
"alwaysOutputData": false
},
{
"id": "dad8f0ba-58c3-4ae7-b3fb-3c9da1f1381c",
"name": "Scrape emails from page",
"type": "n8n-nodes-base.code",
"onError": "continueRegularOutput",
"position": [
-3072,
-704
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const data = $json.data\n\nconst emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.(?!png|jpg|gif|jpeg)[a-zA-Z]{2,}/g\n\nconst emails = data.match(emailRegex)\n\nreturn {json: {emails: emails}}"
},
"typeVersion": 2
},
{
"id": "ada720da-53f7-466c-97b6-26df8ce8cf1b",
"name": "Aggregate arrays of emails",
"type": "n8n-nodes-base.aggregate",
"position": [
-2832,
-816
],
"parameters": {
"options": {
"mergeLists": true
},
"fieldsToAggregate": {
"fieldToAggregate": [
{
"fieldToAggregate": "emails"
}
]
}
},
"typeVersion": 1
},
{
"id": "41e1d8c6-1b97-443a-9a1f-b693c8cc45de",
"name": "Split out into default data structure",
"type": "n8n-nodes-base.splitOut",
"position": [
-2624,
-816
],
"parameters": {
"options": {},
"fieldToSplitOut": "emails"
},
"typeVersion": 1
},
{
"id": "4889d7ff-ad7c-491b-b34f-38b216dde6dc",
"name": "Remove duplicate emails",
"type": "n8n-nodes-base.removeDuplicates",
"position": [
-2400,
-816
],
"parameters": {
"compare": "selectedFields",
"options": {},
"fieldsToCompare": "emails"
},
"typeVersion": 1.1
},
{
"id": "cd15040b-f299-497f-bfa1-3a8cf9e35961",
"name": "Filter irrelevant emails",
"type": "n8n-nodes-base.filter",
"position": [
-2192,
-816
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "041797f2-2fe2-41dc-902a-d34050b9b304",
"operator": {
"type": "string",
"operation": "notRegex"
},
"leftValue": "={{ $json.emails }}",
"rightValue": "=(google|gstatic|ggpht|schema\\.org|example\\.com|sentry\\.wixpress\\.com|sentry-next\\.wixpress\\.com|ingest\\.sentry\\.io|sentry\\.io|imli\\.com)"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "83f04b23-285e-4471-becd-e85e744f9817",
"name": "Save emails to Google Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-2000,
-816
],
"parameters": {
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": ""
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 4.5
},
{
"id": "f8c6cd88-73cf-453e-8911-875641de292f",
"name": "Starts scraper workflow",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"position": [
-4816,
-624
],
"parameters": {},
"typeVersion": 1
},
{
"id": "c2316236-6162-4dca-bec7-5b3533ec5f24",
"name": "Run workflow",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-4864,
-1312
],
"parameters": {},
"typeVersion": 1
},
{
"id": "e3f89abb-8206-4a0a-b60e-7aa3dad854b6",
"name": "Wait between executions",
"type": "n8n-nodes-base.wait",
"position": [
-4160,
-1296
],
"parameters": {
"amount": 2
},
"typeVersion": 1.1
},
{
"id": "a1268f15-ccbb-4061-a1c2-76664290c65e",
"name": "Execute scraper for query",
"type": "n8n-nodes-base.executeWorkflow",
"position": [
-4368,
-1296
],
"parameters": {
"mode": "each",
"options": {
"waitForSubWorkflow": false
},
"workflowId": {
"__rl": true,
"mode": "id",
"value": "={{ $workflow.id }}"
}
},
"typeVersion": 1.1
},
{
"id": "0aecd861-9916-4f9b-b6ec-97eba36bfdc5",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4896,
-1552
],
"parameters": {
"color": 7,
"width": 660,
"height": 564,
"content": "## \ud83d\udee0 Setup\n1. Setup your list of queries in the \"Run workflow\" manual trigger node. Watch this on how to generate the queries with ChatGPT.\n3. Choose a sheet to populate with data in the **Google Sheets node**\n4. Run the workflow and start getting leads into your Google Sheets document"
},
"typeVersion": 1
},
{
"id": "038463ac-4695-4781-8654-9a1fec3def47",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4208,
-1456
],
"parameters": {
"color": 7,
"width": 224,
"height": 356,
"content": "**Wait** \ud83d\udc47\nSet wait time between each query workflow execution. Default is 2 seconds."
},
"typeVersion": 1
},
{
"id": "85ea0ce9-a063-4c52-86e7-ddb76ffbf6dd",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4928,
-944
],
"parameters": {
"color": 7,
"width": 480,
"height": 516,
"content": "## Scraper entry\n\nThis sub-workflow starts when another workflow passes in one search query.\n\nInput expected:\n- `query`\n\nThe flow then:\n1. Searches Google Maps using the query\n2. Extracts possible website URLs\n3. Visits each candidate site\n4. Scrapes email addresses\n5. Cleans and saves results to Google Sheets"
},
"typeVersion": 1
},
{
"id": "0edc10c8-bdb3-4a67-9f33-1dfab359e708",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2048,
-1120
],
"parameters": {
"color": 7,
"height": 500,
"content": "## Output\n\nThis final section appends clean email rows to Google Sheets.\n\nBefore running:\n1. Connect Google Sheets credentials\n2. Select the correct spreadsheet\n3. Select the target sheet tab\n\nEach output row should represent one email record."
},
"typeVersion": 1
},
{
"id": "b574616b-a6e9-45be-baa4-8011b03b9d43",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-5520,
-1536
],
"parameters": {
"color": 7,
"width": 480,
"height": 140,
"content": "## Google Maps Automatic Email Scraper\n\nThis workflow automatically scrapes emails from businesses on Google Maps based on a list of queries that you provide."
},
"typeVersion": 1
},
{
"id": "3222926c-3c66-45f7-83a4-1a3f3b7da489",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4432,
-928
],
"parameters": {
"color": 7,
"width": 576,
"height": 500,
"content": "## URL extraction\n\nThis section pulls URLs from the Google Maps search response.\n\nSteps:\n- Read raw HTML/text response\n- Extract all URLs using regex\n- Filter out junk/system domains\n- Remove duplicate URLs before visiting sites\n\nNote:\nThis depends on Google Maps page HTML, so it may stop working if Google changes the page structure."
},
"typeVersion": 1
},
{
"id": "27630da0-7a10-4810-a279-fe2dc62c949d",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3840,
-1024
],
"parameters": {
"color": 7,
"width": 936,
"height": 596,
"content": "## URL loop\n\nThis loop processes one candidate URL at a time.\n\nFor each URL:\n1. Request the page\n2. Send the page content into the page/email processing flow\n3. Continue until no URLs are left\n\nRecommended:\nUse batch size = 1 for better control and easier debugging."
},
"typeVersion": 1
},
{
"id": "850fbb7e-ba82-4367-b587-7eadcc33d83b",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2880,
-1072
],
"parameters": {
"color": 7,
"width": 816,
"height": 452,
"content": "## Email extraction\n\nThis section extracts email addresses from each fetched web page.\n\nSteps:\n- Read page HTML/text\n- Match emails using regex\n- Aggregate all emails from all processed pages\n- Split them back into one-item-per-email format\n- Remove duplicate and junk emails"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "e1a2ca8d-ceb4-4396-a58a-8d350ab6af2e",
"nodeGroups": [],
"connections": {
"Run workflow": {
"main": [
[
{
"node": "Loop over queries",
"type": "main",
"index": 0
}
]
]
},
"Loop over URLs": {
"main": [
[
{
"node": "Loop over pages",
"type": "main",
"index": 0
}
],
[
{
"node": "Request web page for URL",
"type": "main",
"index": 0
}
]
]
},
"Loop over pages": {
"main": [
[
{
"node": "Aggregate arrays of emails",
"type": "main",
"index": 0
}
],
[
{
"node": "Scrape emails from page",
"type": "main",
"index": 0
}
]
]
},
"Loop over queries": {
"main": [
[],
[
{
"node": "Execute scraper for query",
"type": "main",
"index": 0
}
]
]
},
"Remove Duplicate URLs": {
"main": [
[
{
"node": "Loop over URLs",
"type": "main",
"index": 0
}
]
]
},
"Filter irrelevant URLs": {
"main": [
[
{
"node": "Remove Duplicate URLs",
"type": "main",
"index": 0
}
]
]
},
"Remove duplicate emails": {
"main": [
[
{
"node": "Filter irrelevant emails",
"type": "main",
"index": 0
}
]
]
},
"Scrape emails from page": {
"main": [
[
{
"node": "Loop over pages",
"type": "main",
"index": 0
}
]
]
},
"Starts scraper workflow": {
"main": [
[
{
"node": "Search Google Maps with query",
"type": "main",
"index": 0
}
]
]
},
"Wait between executions": {
"main": [
[
{
"node": "Loop over queries",
"type": "main",
"index": 0
}
]
]
},
"Filter irrelevant emails": {
"main": [
[
{
"node": "Save emails to Google Sheet",
"type": "main",
"index": 0
}
]
]
},
"Request web page for URL": {
"main": [
[
{
"node": "Loop over URLs",
"type": "main",
"index": 0
}
]
]
},
"Scrape URLs from results": {
"main": [
[
{
"node": "Filter irrelevant URLs",
"type": "main",
"index": 0
}
]
]
},
"Execute scraper for query": {
"main": [
[
{
"node": "Wait between executions",
"type": "main",
"index": 0
}
]
]
},
"Aggregate arrays of emails": {
"main": [
[
{
"node": "Split out into default data structure",
"type": "main",
"index": 0
}
]
]
},
"Search Google Maps with query": {
"main": [
[
{
"node": "Scrape URLs from results",
"type": "main",
"index": 0
}
]
]
},
"Split out into default data structure": {
"main": [
[
{
"node": "Remove duplicate emails",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow takes a list of Google Maps search queries, extracts candidate business website URLs from the search results, visits each site, scrapes email addresses from the page content, and appends cleaned, deduplicated emails to Google Sheets fully automated, no manual…
Source: https://n8n.io/workflows/16421/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Google Maps Email Scraper Template. Uses removeDuplicates, splitInBatches, httpRequest, splitOut. Event-driven trigger; 26 nodes.
Email Scapper. Uses httpRequest, googleSheets, executeWorkflowTrigger. Event-driven trigger; 26 nodes.
ITHome比賽進程. Uses httpRequest, googleSheets, executeWorkflowTrigger, n8n. Event-driven trigger; 25 nodes.
25-scrape-business-emails-from-google-maps-without-the-use-of-any-third-party-apis. Uses httpRequest, googleSheets, executeWorkflowTrigger. Event-driven trigger; 23 nodes.
Intelligent URL Validation - Validates PDF URLs before attempting download, extracting filenames from URLs and generating fallback names when needed, preventing wasted processing time Binary File Hand