This workflow corresponds to n8n.io template #14396 — we link there as the canonical source.
This workflow follows the Form 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": "nd7DATAOGIH9jAzL",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Google Maps Lead Gen",
"tags": [],
"nodes": [
{
"id": "e35a6669-bc13-4094-8d7d-7ed1fc3792fe",
"name": "Split Out",
"type": "n8n-nodes-base.splitOut",
"position": [
-64,
-336
],
"parameters": {
"include": "allOtherFields",
"options": {},
"fieldToSplitOut": "results"
},
"typeVersion": 1
},
{
"id": "c61ec1f0-288e-4f57-8ea2-bb5ca9fd18a9",
"name": "Aggregate",
"type": "n8n-nodes-base.aggregate",
"position": [
496,
-384
],
"parameters": {
"include": "specifiedFields",
"options": {},
"aggregate": "aggregateAllItemData"
},
"typeVersion": 1
},
{
"id": "78b79be3-6be6-4dbf-aeb0-b6b47331db5d",
"name": "Forms Trigger",
"type": "n8n-nodes-base.formTrigger",
"position": [
-576,
-416
],
"parameters": {
"options": {},
"formTitle": "SDR",
"formFields": {
"values": [
{
"fieldLabel": "Tipo de Neg\u00f3cio"
},
{
"fieldLabel": "Cidade"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "c3c7a4ff-5c82-45ee-92d7-46540b25b7c4",
"name": "Format Search Query",
"type": "n8n-nodes-base.set",
"position": [
-400,
-416
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "8a6cac17-a468-4d0f-bc8d-c14c6094a983",
"name": "tipoDeNegocio",
"type": "string",
"value": "={{ $json[\"Tipo de Neg\u00f3cio\"] }}"
},
{
"id": "8c5d94b6-c6b6-47c4-8e27-99affc159ade",
"name": "cidade",
"type": "string",
"value": "={{ $json.Cidade }}"
},
{
"id": "09df1334-704f-41de-89e0-257e115903b8",
"name": "api_key",
"type": "string",
"value": "YOUR_API_KEY_HERE"
}
]
}
},
"typeVersion": 3.4,
"alwaysOutputData": true
},
{
"id": "9bc4171b-fe83-40cc-9de1-4d3772d8b7ce",
"name": "Google Maps Text Search",
"type": "n8n-nodes-base.httpRequest",
"notes": "20 leads",
"position": [
-192,
-416
],
"parameters": {
"url": "https://maps.googleapis.com/maps/api/place/textsearch/json",
"options": {
"pagination": {
"pagination": {
"parameters": {
"parameters": [
{
"name": "pagetoken",
"value": "={{ $response.body.next_page_token }}"
}
]
},
"requestInterval": 5000,
"completeExpression": "={{ !$response.body.next_page_token }}",
"paginationCompleteWhen": "other"
}
}
},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "query",
"value": "={{ $json.tipoDeNegocio }} em {{ $json.cidade }}"
},
{
"name": "key",
"value": "={{ $('Format Search Query').item.json.api_key }}"
}
]
}
},
"notesInFlow": true,
"typeVersion": 4.3
},
{
"id": "931de6a9-1f41-4a41-942a-64681747bc2c",
"name": "Fetch Place Details",
"type": "n8n-nodes-base.httpRequest",
"position": [
112,
-336
],
"parameters": {
"url": "https://maps.googleapis.com/maps/api/place/details/json",
"options": {},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "place_id",
"value": "={{ $json.results.place_id }}"
},
{
"name": "fields",
"value": "=name,formatted_phone_number,website"
},
{
"name": "key",
"value": "={{ $('Format Search Query').item.json.api_key }}"
}
]
}
},
"typeVersion": 4.3
},
{
"id": "c4cb172b-e4c2-4944-bbb1-dd6f1a3a7009",
"name": "Merge Original & Details",
"type": "n8n-nodes-base.merge",
"position": [
320,
-384
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "271e2365-e5c8-4822-9dd2-38250cba7be6",
"name": "Data Cleaning Logic",
"type": "n8n-nodes-base.code",
"position": [
640,
-384
],
"parameters": {
"jsCode": "const baseRaw = $items('Google Maps Text Search') || [];\n\n// base\nconst base = baseRaw\n .map(i => i.json?.data || i.json)\n .flat()\n .flatMap(d => d.results || []);\n\n// fun\u00e7\u00e3o pra normalizar texto\nconst normalizar = (str) =>\n (str || '')\n .toLowerCase()\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '') // remove acento\n .replace(/[^a-z0-9]/g, ''); // limpa tudo\n\n// cria mapa com chave composta (nome + endere\u00e7o)\nconst detailsMap = {};\n\n($json.data || []).forEach(d => {\n const r = d.result || {};\n if (!r.name) return;\n\n const chave = normalizar(r.name);\n\n // guarda se tiver telefone ou site\n if (!detailsMap[chave] || r.formatted_phone_number || r.website) {\n detailsMap[chave] = r;\n }\n});\n\n// merge\nconst resultado = base.map(item => {\n const chave = normalizar(item.name);\n const det = detailsMap[chave] || {};\n\n return {\n nome: item?.name,\n tipo: item?.types?.[0],\n endereco: item?.formatted_address,\n latitude: item?.geometry?.location?.lat,\n longitude: item?.geometry?.location?.lng,\n aberto_agora: item?.opening_hours?.open_now ?? false,\n status: item?.business_status,\n avaliacao: item?.rating,\n total_avaliacoes: item?.user_ratings_total,\n\n telefone: det?.formatted_phone_number || null,\n site: det?.website || null\n };\n});\n\nreturn resultado.map(r => ({ json: r }));"
},
"typeVersion": 2
},
{
"id": "51ccbb16-4105-4a2a-9dfa-a213c09527c5",
"name": "Validate Lead Quality",
"type": "n8n-nodes-base.if",
"position": [
848,
-384
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c0e46eb5-5cf6-4d84-b513-38961334cc9c",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.telefone }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "a9048e2a-a723-4716-8d37-2c4d9b825ef8",
"name": "Log Lead to Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
1072,
-384
],
"parameters": {
"columns": {
"value": {
"name": "={{ $json.nome }}",
"site": "={{ $json.site }}",
"types": "={{ $json.tipo }}",
"rating": "={{ $json.avaliacao }}",
"business_status": "={{ $json.status }}",
"formatted_address": "={{ $json.endereco }}",
"location.lat / lng": "={{ $json.latitude }},{{ $json.longitude }}",
"user_ratings_total": "={{ $json.total_avaliacoes }}",
"formatted_phone_number": "={{ $json.telefone }}",
"opening_hours.open_now": "={{ $json.aberto_agora }}"
},
"schema": [
{
"id": "types",
"type": "string",
"display": true,
"required": false,
"displayName": "types",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "name",
"type": "string",
"display": true,
"required": false,
"displayName": "name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "formatted_phone_number",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "formatted_phone_number",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "formatted_address",
"type": "string",
"display": true,
"required": false,
"displayName": "formatted_address",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "location.lat / lng",
"type": "string",
"display": true,
"required": false,
"displayName": "location.lat / lng",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "opening_hours.open_now",
"type": "string",
"display": true,
"required": false,
"displayName": "opening_hours.open_now",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "business_status",
"type": "string",
"display": true,
"required": false,
"displayName": "business_status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "rating",
"type": "string",
"display": true,
"required": false,
"displayName": "rating",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "user_ratings_total",
"type": "string",
"display": true,
"required": false,
"displayName": "user_ratings_total",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "site",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "site",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 228523750,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1jDB07Io7dyxGkBbvNbGfyLdpNSxSAx_uVKbdifTc9BA/edit#gid=228523750",
"cachedResultName": "SRD"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1jDB07Io7dyxGkBbvNbGfyLdpNSxSAx_uVKbdifTc9BA",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1jDB07Io7dyxGkBbvNbGfyLdpNSxSAx_uVKbdifTc9BA/edit?usp=drivesdk",
"cachedResultName": "base"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "dd11a58f-f69a-4cfe-8114-7d23c3107daa",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-608,
-464
],
"parameters": {
"color": 5,
"width": 352,
"height": 256,
"content": "## TRIGGER & INPUT PREP"
},
"typeVersion": 1
},
{
"id": "fb0b7f70-8788-408a-bf16-065ec5ca3755",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-240,
-464
],
"parameters": {
"width": 496,
"height": 272,
"content": "## GOOGLE MAPS ENRICHMENT"
},
"typeVersion": 1
},
{
"id": "b3374948-b2a2-43e2-ae93-1b85aa181ae5",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
272,
-464
],
"parameters": {
"width": 512,
"height": 256,
"content": "## DATA PROCESSING & LOGIC"
},
"typeVersion": 1
},
{
"id": "cd48214e-31f9-4999-9f83-5e711a2c2460",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
800,
-464
],
"parameters": {
"color": 4,
"width": 464,
"height": 256,
"content": "## VALIDATION & STORAGE"
},
"typeVersion": 1
},
{
"id": "53cf972c-96b8-4a2a-8608-e0f8ce32af00",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1072,
-816
],
"parameters": {
"width": 432,
"height": 1008,
"content": "# SDR Google Maps Lead Pipeline\n\n### Objective\nThis workflow is a high-efficiency **B2B Lead Generation engine** built for SDR teams. It automates the process of scouting, enriching, and validating business prospects from **Google Maps** based on custom search criteria (Category + City) and stores them in a structured database for outreach.\n\n---\n\n### How it Works\n\n* **Trigger & Prep**: Starts via an **n8n Form**. A `Set` node cleans the input and prepares the environment variables.\n* **Discovery & Enrichment**: Uses **Google Maps Text Search** with optimized **auto-pagination** (fetching results as long as a `next_page_token` exists).\n* **Granular Fetch**: A `Split Out` node breaks the list into individual items to trigger **Fetch Place Details**, capturing high-value data like `phone_number` and `website`.\n* **Data Intelligence**: A custom **JavaScript Code** node normalizes strings, removes duplicates based on a composite key (Name + Address), and prepares the JSON schema.\n* **Quality Gate**: An `If` node ensures only leads with a **valid phone number** are passed to the final destination.\n\n---\n\n### Tech Stack\n* **Source**: Google Places API (Text Search & Details).\n* **Engine**: n8n Automation.\n* **Storage**: Google Sheets.\n\n---\n"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"timezone": "America/Sao_Paulo",
"callerPolicy": "workflowsFromSameOwner",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "89b5a198-5357-4b54-a0de-e16c57315fa5",
"connections": {
"Aggregate": {
"main": [
[
{
"node": "Data Cleaning Logic",
"type": "main",
"index": 0
}
]
]
},
"Split Out": {
"main": [
[
{
"node": "Fetch Place Details",
"type": "main",
"index": 0
}
]
]
},
"Forms Trigger": {
"main": [
[
{
"node": "Format Search Query",
"type": "main",
"index": 0
}
]
]
},
"Data Cleaning Logic": {
"main": [
[
{
"node": "Validate Lead Quality",
"type": "main",
"index": 0
}
]
]
},
"Fetch Place Details": {
"main": [
[
{
"node": "Merge Original & Details",
"type": "main",
"index": 0
}
]
]
},
"Format Search Query": {
"main": [
[
{
"node": "Google Maps Text Search",
"type": "main",
"index": 0
}
]
]
},
"Validate Lead Quality": {
"main": [
[
{
"node": "Log Lead to Google Sheets",
"type": "main",
"index": 0
}
]
]
},
"Google Maps Text Search": {
"main": [
[
{
"node": "Merge Original & Details",
"type": "main",
"index": 0
},
{
"node": "Split Out",
"type": "main",
"index": 0
}
]
]
},
"Merge Original & Details": {
"main": [
[
{
"node": "Aggregate",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
googleSheetsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow is a powerful B2B Lead Generation engine designed specifically for SDRs (Sales Development Representatives). It automates the entire process of finding, enriching, and qualifying prospects directly from Google Maps based on any industry and location.
Source: https://n8n.io/workflows/14396/ — 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.
This repository contains an SLA-based lead routing workflow built in n8n, designed to ensure fast lead response, fair sales distribution, and controlled escalation without relying on a full CRM system
How it works A form trigger accepts an Industry + Location query (e.g. Accountants London). Text Search Page 1 calls Google Places Text Search to return results and a nextpagetoken. Conditional checks
Agencies, sales teams, and service businesses who want to instantly qualify inbound leads with an AI-powered phone call — no manual follow-up needed.
This n8n template automates lead generation by scraping Google Maps using the Olostep API. It extracts business names, locations, websites, phone numbers, and decision-maker names (CEO, Founder, etc.)
This workflow automates the process of generating niche-specific business leads from Google Maps, leveraging the Google Places API and Google Sheets for seamless data collection and storage. Business