AutomationFlowsMarketing & Ads › Generate City-based Business Leads with Google Maps and Google Sheets

Generate City-based Business Leads with Google Maps and Google Sheets

ByAbdullah Al Shishani @arais415 on n8n.io

This workflow collects business leads from Google Maps by geocoding a user-provided city, searching across a small coordinate grid with Places Nearby Search pagination, and writing enriched business details (name, address, phone, website, ratings) to a Google Sheets spreadsheet.…

Event trigger★★★★☆ complexity25 nodesForm TriggerHTTP RequestGoogle Sheets
Marketing & Ads Trigger: Event Nodes: 25 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #15960 — 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 →

Download .json
{
  "id": "XISpgVifGchaNB1g",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Google Maps Leads - Fully Dynamic City Grid Scraper",
  "tags": [],
  "nodes": [
    {
      "id": "fba8f6eb-dbe1-48b5-a41d-bd7152ecaf08",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        4480,
        1696
      ],
      "parameters": {
        "options": {},
        "formTitle": "Dynamic Business Leads Generator",
        "formFields": {
          "values": [
            {
              "fieldLabel": "What is the Search Term?",
              "requiredField": true
            },
            {
              "fieldLabel": "What City / Location?",
              "placeholder": "e.g., Amman, Dubai, London",
              "requiredField": true
            },
            {
              "fieldType": "number",
              "fieldLabel": "Max Results?",
              "requiredField": true
            },
            {
              "fieldLabel": "Google Maps API Key",
              "requiredField": true
            }
          ]
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "45d586e8-82b9-429d-9bba-564fafa252ce",
      "name": "Set Initial Parameters",
      "type": "n8n-nodes-base.set",
      "position": [
        4672,
        1696
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "assign_api",
              "name": "api_key",
              "type": "string",
              "value": "={{ $json['Google Maps API Key'] }}"
            },
            {
              "id": "assign_keyword",
              "name": "keyword",
              "type": "string",
              "value": "={{ $json['What is the Search Term?'] }}"
            },
            {
              "id": "assign_city",
              "name": "targetCity",
              "type": "string",
              "value": "={{ $json['What City / Location?'] }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "9945f6d5-159a-4d82-aa5f-fafe6e5c6f7a",
      "name": "Geocode Target City",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        4880,
        1696
      ],
      "parameters": {
        "url": "https://maps.googleapis.com/maps/api/geocode/json",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "address",
              "value": "={{ $json.targetCity }}"
            },
            {
              "name": "key",
              "value": "={{ $json.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "870fc807-fe7d-475d-a29b-2bb31584abc7",
      "name": "Generate Dynamic Grid",
      "type": "n8n-nodes-base.set",
      "position": [
        5088,
        1696
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "grid_calc",
              "name": "locations",
              "type": "array",
              "value": "={{ \n  (function() {\n    const lat = parseFloat($json.results[0].geometry.location.lat);\n    const lng = parseFloat($json.results[0].geometry.location.lng);\n    \n    const offset = 0.025;\n    \n    return [\n      `${lat},${lng}`,\n      `${(lat + offset).toFixed(4)},${(lng - offset).toFixed(4)}`,\n      `${(lat - offset).toFixed(4)},${(lng + offset).toFixed(4)}`,\n      `${(lat + offset).toFixed(4)},${(lng + offset).toFixed(4)}` \n    ];\n  })()\n}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "85d994f0-cf12-4d35-b465-7eafb1eed257",
      "name": "Split Locations",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        5280,
        1696
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "locations"
      },
      "typeVersion": 1
    },
    {
      "id": "7c1247cc-f45c-4eb7-af1e-8cdf215f337e",
      "name": "Search Page 1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        4480,
        2016
      ],
      "parameters": {
        "url": "https://maps.googleapis.com/maps/api/place/nearbysearch/json",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "location",
              "value": "={{ $json.locations }}"
            },
            {
              "name": "radius",
              "value": "5000"
            },
            {
              "name": "keyword",
              "value": "={{ $('Set Initial Parameters').item.json.keyword }}"
            },
            {
              "name": "key",
              "value": "={{ $('Set Initial Parameters').item.json.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "11e45d28-0a07-424d-b821-76b3969189ff",
      "name": "Save Page 1",
      "type": "n8n-nodes-base.set",
      "position": [
        4672,
        2016
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "p1_res",
              "name": "page1_results",
              "type": "array",
              "value": "={{ $json.results }}"
            },
            {
              "id": "p1_tok",
              "name": "next_page_token_1",
              "type": "string",
              "value": "={{ $json.next_page_token ?? '' }}"
            },
            {
              "id": "p1_key",
              "name": "api_key",
              "type": "string",
              "value": "={{ $('Set Initial Parameters').item.json.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "2c527621-b1e5-4590-8eab-5a40d59289f6",
      "name": "Wait for Page 2",
      "type": "n8n-nodes-base.wait",
      "position": [
        4880,
        2016
      ],
      "parameters": {
        "amount": 2
      },
      "typeVersion": 1.1
    },
    {
      "id": "e7d8bca5-1e44-4765-9c0c-6c01207583ef",
      "name": "Search Page 2",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        5088,
        2016
      ],
      "parameters": {
        "url": "https://maps.googleapis.com/maps/api/place/nearbysearch/json",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "pagetoken",
              "value": "={{ $json.next_page_token_1 }}"
            },
            {
              "name": "key",
              "value": "={{ $json.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "f40fa975-221a-4e18-9a56-e8b3414f003a",
      "name": "Save Page 2",
      "type": "n8n-nodes-base.set",
      "position": [
        5280,
        2016
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "p2_p1",
              "name": "page1_results",
              "type": "array",
              "value": "={{ $('Save Page 1').item.json.page1_results }}"
            },
            {
              "id": "p2_res",
              "name": "page2_results",
              "type": "array",
              "value": "={{ $json.results }}"
            },
            {
              "id": "p2_tok",
              "name": "next_page_token_2",
              "type": "string",
              "value": "={{ $json.next_page_token ?? '' }}"
            },
            {
              "id": "p2_key",
              "name": "api_key",
              "type": "string",
              "value": "={{ $('Save Page 1').item.json.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f0b1816e-e670-4de4-b428-481fa4fe60fe",
      "name": "Wait for Page 3",
      "type": "n8n-nodes-base.wait",
      "position": [
        5472,
        2016
      ],
      "parameters": {
        "amount": 2
      },
      "typeVersion": 1.1
    },
    {
      "id": "36a2cf89-3901-40a2-a228-a2adb6193b74",
      "name": "Search Page 3",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        5664,
        2016
      ],
      "parameters": {
        "url": "https://maps.googleapis.com/maps/api/place/nearbysearch/json",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "pagetoken",
              "value": "={{ $json.next_page_token_2 }}"
            },
            {
              "name": "key",
              "value": "={{ $json.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "2dba8fb8-2271-46df-b63e-afe26d8ffbe0",
      "name": "Merge All Pages",
      "type": "n8n-nodes-base.set",
      "position": [
        5856,
        2016
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "merge_all",
              "name": "all_results",
              "type": "array",
              "value": "={{ [...($('Save Page 2').item.json.page1_results || []), ...($('Save Page 2').item.json.page2_results || []), ...($json.results || [])] }}"
            },
            {
              "id": "merge_key",
              "name": "api_key",
              "type": "string",
              "value": "={{ $('Save Page 2').item.json.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "c5764931-1ed8-4a41-b734-58ff675ebc42",
      "name": "Split All Results",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        4480,
        2368
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "all_results"
      },
      "typeVersion": 1
    },
    {
      "id": "2b10909d-2b81-4236-9b45-273ae0e555b2",
      "name": "Collect All Place IDs",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        4672,
        2368
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "places"
      },
      "typeVersion": 1
    },
    {
      "id": "e8aef02e-a3ff-40fa-ad31-2cdc32a58526",
      "name": "Split Places",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        4880,
        2368
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "places"
      },
      "typeVersion": 1
    },
    {
      "id": "37a2b718-0a34-44bd-8fda-955c067e45d9",
      "name": "Loop Over Places",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        5088,
        2368
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "7b0397e3-2ff5-40c3-9119-aee2d2455b19",
      "name": "Get Place Details",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        5280,
        2448
      ],
      "parameters": {
        "url": "https://maps.googleapis.com/maps/api/place/details/json",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "place_id",
              "value": "={{ $json.place_id }}"
            },
            {
              "name": "fields",
              "value": "name,formatted_address,formatted_phone_number,international_phone_number,website,rating,user_ratings_total,types,business_status"
            },
            {
              "name": "key",
              "value": "={{ $('Set Initial Parameters').first().json.api_key }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "44c99c26-377e-49ab-a91c-a2988a470a76",
      "name": "Map Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        5472,
        2448
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "map_name",
              "name": "Name",
              "type": "string",
              "value": "={{ $json.result.name ?? '' }}"
            },
            {
              "id": "map_address",
              "name": "Address",
              "type": "string",
              "value": "={{ $json.result.formatted_address ?? '' }}"
            },
            {
              "id": "map_phone",
              "name": "Phone",
              "type": "string",
              "value": "={{ $json.result.formatted_phone_number ?? '' }}"
            },
            {
              "id": "map_int_phone",
              "name": "International Phone",
              "type": "string",
              "value": "={{ $json.result.international_phone_number ?? '' }}"
            },
            {
              "id": "map_web",
              "name": "Website",
              "type": "string",
              "value": "={{ $json.result.website ?? '' }}"
            },
            {
              "id": "map_rating",
              "name": "Rating",
              "type": "string",
              "value": "={{ $json.result.rating ?? '' }}"
            },
            {
              "id": "map_reviews",
              "name": "Total Reviews",
              "type": "string",
              "value": "={{ $json.result.user_ratings_total ?? '' }}"
            },
            {
              "id": "map_status",
              "name": "Business Status",
              "type": "string",
              "value": "={{ $json.result.business_status ?? '' }}"
            },
            {
              "id": "map_types",
              "name": "Types",
              "type": "string",
              "value": "={{ ($json.result.types ?? []).join(', ') }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "9c5b9e9c-d910-49cf-b502-96e2e5998fd6",
      "name": "Append row in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        5280,
        2272
      ],
      "parameters": {
        "columns": {
          "value": {
            "Website": "={{ $json.Website }}",
            "Category": "={{ $('Set Initial Parameters').item.json.keyword }}",
            "Full Number": "={{ $json['International Phone'] }}",
            "Company Name": "={{ $json.Name }}",
            "Phone Number": "={{ $json.Phone }}",
            "Company Address": "={{ $json.Address }}"
          },
          "schema": [
            {
              "id": "Company Name",
              "type": "string",
              "displayName": "Company Name"
            },
            {
              "id": "Company Address",
              "type": "string",
              "displayName": "Company Address"
            },
            {
              "id": "Category",
              "type": "string",
              "displayName": "Category"
            },
            {
              "id": "Website",
              "type": "string",
              "displayName": "Website"
            },
            {
              "id": "Phone Number",
              "type": "string",
              "displayName": "Phone Number"
            },
            {
              "id": "Full Number",
              "type": "string",
              "displayName": "Full Number"
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1c7q0UWW6Y1rbqNsrXEColIMqaykJYV8Be6a9TcDuIL4/edit#gid=0",
          "cachedResultName": "Dump"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1c7q0UWW6Y1rbqNsrXEColIMqaykJYV8Be6a9TcDuIL4",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1c7q0UWW6Y1rbqNsrXEColIMqaykJYV8Be6a9TcDuIL4/edit?usp=drivesdk",
          "cachedResultName": "Telesales Master Sheet "
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "d85eae39-7fbf-4fa6-bf3f-0cf86a11a127",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3952,
        1616
      ],
      "parameters": {
        "width": 400,
        "height": 672,
        "content": "## Automate business lead generation with a dynamic city grid scraper\nThis workflow helps sales teams and lead generation specialists automatically extract targeted business details from Google Maps without manual searching. It uses a dynamic geographic grid system to bypass standard API result limitations, gathers rich contact information, and streams leads automatically into a master spreadsheet.\n \n**How it works**\n**Initialize search parameters** The workflow triggers via a user-facing form, capturing the target business type, city, and API key.\n\n**Generate dynamic geographic** grid The target city is geocoded into precise coordinates. A custom script automatically builds a 4-point overlapping coordinate grid to maximize search coverage.\n\n**Deep 3-page paginated search** The workflow loops through each grid point and executes up to 3 consecutive pages of deep searches, respecting mandatory API delays to extract every available lead.\n\n**Extract rich profile details** It isolates unique Place IDs to avoid duplicates, then automatically fetches advanced fields like websites, formatted phone numbers, ratings, and business status.\n\n**Stream directly to sheet** All sanitized data is mapped perfectly and streamed row-by-row into a master Google Sheet in real time."
      },
      "typeVersion": 1
    },
    {
      "id": "26567ebe-1e07-40aa-af45-e121983394d5",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3952,
        2304
      ],
      "parameters": {
        "width": 400,
        "height": 288,
        "content": "**Setup steps**\n**Connect Google Sheets** and select your master telesales spreadsheet and target tab.\n\nEnsure your **Google Cloud Console project** has the Geocoding API and Places API enabled.\n\n**Generate a Google Maps API key** to use in the form input.\n\n**Run a test execution** to generate the unique form URL for daily use.\n\n**(Optional)** Customize the geographic coordinate offset inside the grid calculator node to expand or narrow the search area."
      },
      "typeVersion": 1
    },
    {
      "id": "a01fd9e4-39c0-4ea2-a87b-e264c602b267",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4432,
        1632
      ],
      "parameters": {
        "color": 4,
        "width": 1024,
        "height": 256,
        "content": "## Input & File Handling ##"
      },
      "typeVersion": 1
    },
    {
      "id": "ee4b2f4b-bb11-4149-b7c6-23c9c39d435e",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4432,
        1936
      ],
      "parameters": {
        "color": 3,
        "width": 1600,
        "height": 272,
        "content": "## Deep Search & Pagination ##"
      },
      "typeVersion": 1
    },
    {
      "id": "12ed1553-5807-4321-b801-0aa37f70ec5d",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4432,
        2256
      ],
      "parameters": {
        "color": 6,
        "width": 1216,
        "height": 384,
        "content": "## Extraction & Delivery ##"
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "a8b85d8a-af27-43eb-802d-d6be9a522ede",
  "connections": {
    "Map Fields": {
      "main": [
        [
          {
            "node": "Loop Over Places",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Page 1": {
      "main": [
        [
          {
            "node": "Wait for Page 2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Page 2": {
      "main": [
        [
          {
            "node": "Wait for Page 3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Places": {
      "main": [
        [
          {
            "node": "Loop Over Places",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Page 1": {
      "main": [
        [
          {
            "node": "Save Page 1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Page 2": {
      "main": [
        [
          {
            "node": "Save Page 2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Page 3": {
      "main": [
        [
          {
            "node": "Merge All Pages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge All Pages": {
      "main": [
        [
          {
            "node": "Split All Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Locations": {
      "main": [
        [
          {
            "node": "Search Page 1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Page 2": {
      "main": [
        [
          {
            "node": "Search Page 2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Page 3": {
      "main": [
        [
          {
            "node": "Search Page 3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Places": {
      "main": [
        [
          {
            "node": "Append row in sheet",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get Place Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Place Details": {
      "main": [
        [
          {
            "node": "Map Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split All Results": {
      "main": [
        [
          {
            "node": "Collect All Place IDs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "Set Initial Parameters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append row in sheet": {
      "main": [
        []
      ]
    },
    "Geocode Target City": {
      "main": [
        [
          {
            "node": "Generate Dynamic Grid",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Collect All Place IDs": {
      "main": [
        [
          {
            "node": "Split Places",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Dynamic Grid": {
      "main": [
        [
          {
            "node": "Split Locations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Initial Parameters": {
      "main": [
        [
          {
            "node": "Geocode Target City",
            "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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow collects business leads from Google Maps by geocoding a user-provided city, searching across a small coordinate grid with Places Nearby Search pagination, and writing enriched business details (name, address, phone, website, ratings) to a Google Sheets spreadsheet.…

Source: https://n8n.io/workflows/15960/ — original creator credit. Request a take-down →

More Marketing & Ads workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Marketing & Ads

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

Form Trigger, Google Sheets, Slack +1
Marketing & Ads

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

HTTP Request, Form Trigger, Google Sheets
Marketing & Ads

Agencies, sales teams, and service businesses who want to instantly qualify inbound leads with an AI-powered phone call — no manual follow-up needed.

Form Trigger, Google Sheets, HTTP Request
Marketing & Ads

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.)

Form Trigger, HTTP Request, Google Sheets
Marketing & Ads

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 prospec

Form Trigger, HTTP Request, Google Sheets