AutomationFlowsMarketing & Ads › Extract Business Leads from Google Maps to Google Sheets

Extract Business Leads from Google Maps to Google Sheets

Original n8n title: Extract Business Contact Leads From Google Maps with Rapidapi and Google Sheets

ByJavier Hita @javierhita on n8n.io

Follow me on LinkedIn for more!

Event trigger★★★★☆ complexity16 nodesHTTP RequestGoogle Sheets
Marketing & Ads Trigger: Event Nodes: 16 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #5794 — we link there as the canonical source.

This workflow follows the Google Sheets → HTTP Request 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
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "a4df4dee-6fda-4051-99d0-63824e197820",
      "name": "Start Lead Generation",
      "type": "n8n-nodes-base.manualTrigger",
      "notes": "\ud83d\ude80 Click here to start extracting Google Maps business leads. Ensure your search criteria are configured in the Google Sheets 'keyword_searches' tab first.",
      "position": [
        -360,
        -320
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "51c45a00-0d87-4ff0-836c-5354e332f802",
      "name": "Configure Search Parameters",
      "type": "n8n-nodes-base.set",
      "notes": "\u2699\ufe0f Prepares API search parameters from Google Sheets data. Modify the limit (max 100) and other parameters as needed for your use case.",
      "position": [
        1100,
        -300
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "b7344336-0887-40f5-b853-276eb1dba1bf",
              "name": "search",
              "type": "string",
              "value": "={{ $json.query }}"
            },
            {
              "id": "1eb2f614-e6e7-4b0f-bc39-02ce929873e6",
              "name": "latitude",
              "type": "string",
              "value": "={{ $json.lat }}"
            },
            {
              "id": "0cf94d77-ef0d-4b06-bbb1-c3040dd60a24",
              "name": "longitude",
              "type": "string",
              "value": "={{ $json.lon }}"
            },
            {
              "id": "0fc8e386-f81a-44b4-a5c4-162c1d85fd46",
              "name": "region",
              "type": "string",
              "value": "={{ $json.country_iso_code }}"
            },
            {
              "id": "c368eb39-dfc9-4790-987f-b97fd0297245",
              "name": "language",
              "type": "string",
              "value": "EN"
            },
            {
              "id": "cdb5db50-6d2f-4b80-9e47-4ace539290ba",
              "name": "zoom",
              "type": "string",
              "value": "13"
            },
            {
              "id": "d47e2e85-bcc8-48d0-a8a2-8b1d04bd2a16",
              "name": "limit",
              "type": "string",
              "value": "100"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e6385c2d-4f61-495a-93ab-766541fa4579",
      "name": "Google Maps API Request",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "\ud83d\uddfa\ufe0f Calls RapidAPI's Local Business Data service to extract comprehensive business information from Google Maps, including emails and social media contacts.",
      "onError": "continueRegularOutput",
      "position": [
        1460,
        -300
      ],
      "parameters": {
        "url": "https://local-business-data.p.rapidapi.com/search-in-area",
        "options": {},
        "jsonQuery": "={\"query\":\"{{ $json.search }}\"\n  ,\"lat\":\"{{ $json.latitude }}\"\n  ,\"lng\":\"{{ $json.longitude }}\"\n  ,\"zoom\":\"{{ $json.zoom }}\"\n  ,\"limit\":\"{{ $json.limit }}\"\n  ,\"language\":\"{{ $json.language }}\"\n  ,\"region\":\"{{ $json.region }}\"\n  ,\"extract_emails_and_contacts\":\"true\"} ",
        "sendQuery": true,
        "specifyQuery": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "5ddb7eca-5989-4572-9ef6-d7f74f566b33",
      "name": "Parse Business Data",
      "type": "n8n-nodes-base.code",
      "notes": "\ud83d\udd04 Processes API response and extracts all business information including contact details, social media profiles, and location data into a structured format.",
      "position": [
        1800,
        -300
      ],
      "parameters": {
        "jsCode": "// Get the input data\nconst inputData = $input.first().json;\n\n// Try to find the data array and parameters\nlet data, parameters;\n\n// Check if inputData is the array directly\nif (Array.isArray(inputData)) {\n  // If inputData is an array, look for the object with data property\n  const dataObj = inputData.find(item => item.data);\n  if (dataObj) {\n    data = dataObj.data;\n    parameters = dataObj.parameters;\n  }\n} else if (inputData.data) {\n  // If inputData is an object with data property\n  data = inputData.data;\n  parameters = inputData.parameters;\n}\n\n// If we still don't have data, return an error\nif (!data || !Array.isArray(data)) {\n  return [{ json: { error: \"Could not find data array\", inputStructure: Object.keys(inputData) } }];\n}\n\n// Helper function to extract emails as comma-separated string\nfunction extractEmails(emailsArray) {\n  if (!emailsArray || !Array.isArray(emailsArray) || emailsArray.length === 0) {\n    return null;\n  }\n  return emailsArray.join(', ');\n}\n\n// Process each business\nconst outputData = data.map(business => ({\n  // Search parameters\n  query: parameters?.query || null,\n  language: parameters?.language || null,\n  lat: parameters?.lat || null,\n  lon: parameters?.lng || parameters?.lon || null,\n  zoom: parameters?.zoom || null,\n  limit: parameters?.limit || null,\n  \n  // Business data\n  business_id: business.business_id || null,\n  place_id: business.place_id || null,\n  phone_number: business.phone_number || null,\n  name: business.name || null,\n  full_address: business.full_address || null,\n  review_count: business.review_count || null,\n  rating: business.rating || null,\n  website: business.website || null,\n  verified: business.verified || null,\n  type: business.type || null,\n  reviews_link: business.reviews_link || null,\n  place_link: business.place_link || null,\n  about_summary: business.about?.summary || null,\n  address: business.address || null,\n  price_level: business.price_level || null,\n  district: business.district || null,\n  street_address: business.street_address || null,\n  city: business.city || null,\n  zipcode: business.zipcode || null,\n  state: business.state || null,\n  country: business.country || null,\n  \n  // Extract emails and social media contacts\n  email: extractEmails(business.emails_and_contacts?.emails),\n  linkedin: business.emails_and_contacts?.linkedin || null,\n  instagram: business.emails_and_contacts?.instagram || null,\n  \n  // Additional social media fields\n  facebook: business.emails_and_contacts?.facebook || null,\n  twitter: business.emails_and_contacts?.twitter || null,\n  youtube: business.emails_and_contacts?.youtube || null,\n  tiktok: business.emails_and_contacts?.tiktok || null,\n  pinterest: business.emails_and_contacts?.pinterest || null,\n  snapchat: business.emails_and_contacts?.snapchat || null,\n  github: business.emails_and_contacts?.github || null,\n  yelp: business.emails_and_contacts?.yelp || null,\n  \n  // Additional phone numbers from emails_and_contacts\n  additional_phones: business.emails_and_contacts?.phone_numbers?.length > 0 \n    ? business.emails_and_contacts.phone_numbers.join(', ') \n    : null\n}));\n\n// Return the processed data\nreturn outputData.map(item => ({ json: item }));"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "e88dbb0c-d2d6-4a3b-a4c1-0862a2755f4a",
      "name": "Load Search Criteria",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "\ud83d\udccb Reads search criteria from the 'keyword_searches' sheet. Only processes rows marked with 'X' in the 'select' column for targeted lead generation.",
      "position": [
        80,
        -540
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "X",
              "lookupColumn": "select"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "keyword_searches"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "c7deb7f2-0df6-4929-9996-7e17bc6c493a",
      "name": "Process Each Location",
      "type": "n8n-nodes-base.splitInBatches",
      "notes": "\ud83d\udd04 Loops through each selected search criteria to avoid overwhelming the API and ensure reliable processing of multiple locations.",
      "position": [
        740,
        -320
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "932ee9e5-1924-4fa1-b7ed-b76817d8d1a0",
      "name": "Save New Leads",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "\ud83d\udcbe Saves only new business leads to the 'stores_data' sheet. Duplicates are filtered out by the previous merge step.",
      "position": [
        2100,
        -300
      ],
      "parameters": {
        "columns": {
          "value": {
            "lat": "={{ $json.lat }}",
            "lon": "={{ $json.lon }}",
            "city": "={{ $json.city }}",
            "name": "={{ $json.name }}",
            "type": "={{ $json.type }}",
            "zoom": "={{ $json.zoom }}",
            "email": "={{ $json.email }}",
            "limit": "={{ $json.limit }}",
            "query": "={{ $json.query }}",
            "state": "={{ $json.state }}",
            "rating": "={{ $json.rating }}",
            "address": "={{ $json.full_address }}",
            "country": "={{ $json.country }}",
            "website": "={{ $json.website }}",
            "district": "={{ $json.district }}",
            "language": "={{ $json.language }}",
            "linkedin": "={{ $json.linkedin }}",
            "place_id": "={{ $json.place_id }}",
            "verified": "={{ $json.verified }}",
            "zip_code": "={{ $json.zipcode }}",
            "instagram": "={{ $json.instagram }}",
            "place_link": "={{ $json.place_link }}",
            "business_id": "={{ $json.business_id }}",
            "price_level": "={{ $json.price_level }}",
            "full_address": "={{ $json.full_address }}",
            "phone_number": "={{ $json.phone_number }}",
            "review_count": "={{ $json.review_count }}",
            "reviews_link": "={{ $json.reviews_link }}",
            "about_summary": "={{ $json.about_summary }}",
            "street_address": "={{ $json.street_address }}",
            "additional_phones": "={{ $json.additional_phones }}"
          },
          "schema": [
            {
              "id": "business_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "business_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "query",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "query",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone_number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "phone_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "website",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "website",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "full_address",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "full_address",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "rating",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "rating",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "linkedin",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "linkedin",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "instagram",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "instagram",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "stores_data"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "8a36189b-b07f-4af1-bc55-f0c835251927",
      "name": "Rate Limit Delay",
      "type": "n8n-nodes-base.wait",
      "notes": "\u23f1\ufe0f 10-second delay between API calls to respect rate limits and prevent being blocked. Adjust timing based on your API plan.",
      "position": [
        2100,
        -20
      ],
      "parameters": {
        "amount": 10
      },
      "typeVersion": 1.1
    },
    {
      "id": "53044569-b459-4825-8ce5-a82c2d80fb45",
      "name": "Load Existing Leads",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "\ud83d\udcca Reads existing leads from the database to enable duplicate detection and prevent re-processing the same businesses.",
      "position": [
        60,
        -40
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "stores_data"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "511e0baf-8741-431f-9c88-b2e2237b9ebb",
      "name": "Filter New Searches",
      "type": "n8n-nodes-base.merge",
      "notes": "\ud83d\udd0d Smart duplicate prevention: Only processes search criteria that haven't been executed before, saving API calls and avoiding duplicate data.",
      "position": [
        440,
        -320
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "joinMode": "keepNonMatches",
        "outputDataFrom": "input1",
        "fieldsToMatchString": "query, lat"
      },
      "typeVersion": 3.2
    },
    {
      "id": "73efc100-3000-4936-a67b-30bdde13ba7d",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -840,
        -520
      ],
      "parameters": {
        "color": 4,
        "width": 400,
        "height": 620,
        "content": "# Google Maps Lead Generation Workflow\n\n## \ud83c\udfaf **Overview**\nThis workflow extracts business leads from Google Maps with contact information and stores them in Google Sheets with intelligent duplicate prevention.\n\n## \ud83d\udccb **Before Starting:**\n1. Set up RapidAPI account with Local Business Data API\n2. Create Google Sheet with 'keyword_searches' and 'stores_data' tabs\n3. Configure credentials in n8n\n4. Add your search queries to Google Sheets\n\n## \ud83d\ude80 **How to Use:**\n- Mark search queries with 'X' in select column\n- Click 'Start Lead Generation' to begin\n- Workflow automatically prevents duplicates\n- Results saved to 'stores_data' sheet"
      },
      "typeVersion": 1
    },
    {
      "id": "45ee9c11-3bf7-44dc-8359-cedf43e7c100",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -280,
        -940
      ],
      "parameters": {
        "color": 5,
        "width": 350,
        "height": 400,
        "content": "## \ud83d\udcca **INPUT DATA STRUCTURE**\n\n**keyword_searches** sheet columns:\n```\n| select | query | lat | lon | country_iso_code |\n|--------|-------|-----|-----|------------------|\n| X | Restaurants Madrid | 40.4168 | -3.7038 | ES |\n| X | Hair Salons NYC | 40.7589 | -73.9851 | US |\n```\n\n**Tips:**\n- Use 'X' to mark queries for processing\n- Be specific with search terms\n- Include accurate coordinates\n- Use 2-letter country codes"
      },
      "typeVersion": 1
    },
    {
      "id": "96e90ea0-93e3-4f95-a51a-1d37c17c4476",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        340,
        -740
      ],
      "parameters": {
        "color": 6,
        "width": 320,
        "height": 740,
        "content": "## \ud83d\udd04 **DUPLICATE PREVENTION**\n\nThis workflow has **2-level duplicate prevention:**\n\n**Level 1: Search Level**\n- Compares new queries with existing data\n- Skips queries already processed\n- Saves API costs (50-80% reduction)\n\n**Level 2: Business Level**\n- Each business has unique business_id\n- Prevents duplicate business entries\n- Maintains data integrity"
      },
      "typeVersion": 1
    },
    {
      "id": "a31ffc0b-2bdd-419c-97b9-583af5b91e3a",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        960,
        -520
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 200,
        "content": "## \u2699\ufe0f **API CONFIGURATION**\n\n**Search Parameters:**\n- **Limit**: 100 results max per query\n- **Zoom**: 13 (city-wide) to 18 (local)\n- **Language**: EN, ES, FR, etc.\n- **Extract Contacts**: Always enabled\n\n**Rate Limiting:**\n- 10 seconds between requests\n- Prevents API blocking\n- Adjustable based on your plan"
      },
      "typeVersion": 1
    },
    {
      "id": "20ddcaad-738a-4bed-93ff-c7a044c3fc21",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1420,
        -720
      ],
      "parameters": {
        "color": 5,
        "width": 540,
        "height": 400,
        "content": "## \ud83d\udcf1 **EXTRACTED DATA**\n\n**Business Information:**\n- Name, address, phone, website\n- Rating, reviews, verification status\n- Business type, price level\n\n**Contact Details:**\n- Email addresses\n- LinkedIn, Instagram profiles\n- Facebook, Twitter, YouTube\n- Additional phone numbers\n\n**Location Data:**\n- Full address, coordinates\n- City, state, country, zip code"
      },
      "typeVersion": 1
    },
    {
      "id": "20ccaa92-bf61-4f75-a81b-d6b1e0f550b5",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2160,
        -660
      ],
      "parameters": {
        "color": 3,
        "width": 350,
        "height": 340,
        "content": "## \ud83d\udcc8 **EXECUTION FLOW**\n\n**1.** Load search criteria (marked with X)\n**2.** Load existing leads for comparison\n**3.** Filter out already processed searches\n**4.** Loop through each new search\n**5.** Configure API parameters\n**6.** Call Google Maps API\n**7.** Parse and structure data\n**8.** Save new leads to sheet\n**9.** Wait 10 seconds (rate limiting)\n**10.** Continue to next search\n\n\u2705 **Result**: Clean, organized lead database without duplicates!"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Save New Leads": {
      "main": [
        [
          {
            "node": "Rate Limit Delay",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rate Limit Delay": {
      "main": [
        [
          {
            "node": "Process Each Location",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter New Searches": {
      "main": [
        [
          {
            "node": "Process Each Location",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load Existing Leads": {
      "main": [
        [
          {
            "node": "Filter New Searches",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Parse Business Data": {
      "main": [
        [
          {
            "node": "Save New Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load Search Criteria": {
      "main": [
        [
          {
            "node": "Filter New Searches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Each Location": {
      "main": [
        [],
        [
          {
            "node": "Configure Search Parameters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Start Lead Generation": {
      "main": [
        [
          {
            "node": "Load Search Criteria",
            "type": "main",
            "index": 0
          },
          {
            "node": "Load Existing Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Maps API Request": {
      "main": [
        [
          {
            "node": "Parse Business Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Configure Search Parameters": {
      "main": [
        [
          {
            "node": "Google Maps API Request",
            "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

Follow me on LinkedIn for more!

Source: https://n8n.io/workflows/5794/ — 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 n8n workflow automates the process of finding ecommerce seller leads, enriching them with product and business details, discovering company websites, and extracting contact information such as em

Google Sheets, N8N Nodes Mrscraper, HTTP Request
Marketing & Ads

This template is for B2B sales teams, SDRs, growth marketers, and founders who maintain a spreadsheet of prospects and need verified contact details -- emails and mobile numbers -- without manual rese

Google Sheets, HTTP Request
Marketing & Ads

This workflow finds local businesses from Google Maps and automatically enriches them with emails, social profiles, AI summaries, and personalized outreach messages — all saved to Google Sheets. Searc

HTTP Request, Google Sheets
Marketing & Ads

This workflow leverages n8n to perform automated Google Maps API queries and manage data efficiently in Google Sheets. It's designed to extract specific location data based on a given list of ZIP code

Execute Workflow Trigger, Stop And Error, HTTP Request +1
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