{
  "id": "scrapeer-google-maps-leads-to-google-sheets",
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "name": "Google Maps Lead Enrichment to Google Sheets with Scrapeer",
  "tags": [],
  "nodes": [
    {
      "id": "9cc7b05c-3f91-45d0-bcf7-a9865fd3001d",
      "name": "Template Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -800,
        -840
      ],
      "parameters": {
        "color": 1,
        "width": 900,
        "height": 820,
        "content": "# Enrich Google Maps business leads with Scrapeer and Google Sheets\n\nSearch Google Maps for a business category and location, enrich each listing with contact and reputation data, and append one clean row per business to Google Sheets. Scrapeer runs the cloud browser: it searches Google Maps, removes duplicate businesses, visits detail pages, and enriches each lead. n8n handles inputs, scheduling, row preparation, and Google Sheets delivery.\n\n## How it works\n1. **Manual Test** or **Daily Schedule** starts the workflow.\n2. **Set Search Inputs** defines the search query, location, result limit, and spreadsheet name.\n3. **Scrapeer** searches Google Maps, deduplicates the businesses, enriches each lead from its detail page, and returns the completed Cloud Run.\n4. **Prepare Google Sheets Rows** turns the enriched lead list into one n8n item per business and protects text values for Sheets.\n5. **Google Sheets** appends each prepared lead to the selected tab.\n\n## Setup\n- [ ] Install `@scrapeer/n8n-nodes-scrapeer` and add a Scrapeer API credential.\n- [ ] In Scrapeer, create a Flow from the **Google Maps Leads** template.\n- [ ] Select that saved Flow in **Scrapeer: Search and Enrich Leads**.\n- [ ] Create a Google Sheet with a **Leads** tab. Add these columns: Scraped At, Search Query, Location, Name, Category, Rating, Reviews, Address, Phone, Website, Google Maps URL.\n- [ ] Add a Google Sheets service account credential, share the Sheet with its service account email, then select the document and Leads tab.\n- [ ] Set `searchQuery`, `location`, `maxResults`, and `spreadsheetName`.\n- [ ] Start with 10-25 results and run **Manual Test** before activating the workflow.\n\n## Customize\nChange the search inputs or schedule. If your Scrapeer Flow returns different fields, update **Prepare Google Sheets Rows** and the Google Sheets column mapping."
      },
      "typeVersion": 1
    },
    {
      "id": "15b68d79-e68c-4143-805e-69b3858ce6bf",
      "name": "Section 1: Trigger and Inputs",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -800,
        40
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 500,
        "content": "# 1. Choose how the workflow starts\n\nRun manually while testing. Activate the workflow only when you are ready to use the daily 08:00 schedule."
      },
      "typeVersion": 1
    },
    {
      "id": "deaf339f-a138-4dcf-aa64-c77332f138ff",
      "name": "Section 2: Scrape and Prepare Rows",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -40,
        40
      ],
      "parameters": {
        "color": 7,
        "width": 880,
        "height": 500,
        "content": "# 2. Search and enrich with Scrapeer\n\nScrapeer searches, removes duplicate businesses, and enriches each lead from its Google Maps detail page. n8n then prepares the returned list as Sheet rows."
      },
      "typeVersion": 1
    },
    {
      "id": "6c0a8fea-9691-4745-a833-20f2ad41f89b",
      "name": "Section 3: Save Leads",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        880,
        40
      ],
      "parameters": {
        "color": 7,
        "width": 420,
        "height": 500,
        "content": "# 3. Append to Google Sheets\n\nEach prepared lead becomes one row in the selected Leads tab."
      },
      "typeVersion": 1
    },
    {
      "id": "52d55bd3-341c-41db-afd7-7419071a72ad",
      "name": "Manual Test",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -680,
        200
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "3afd835c-59b0-4710-8c8a-f383551df465",
      "name": "Daily Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -680,
        380
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 8
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "a122ace1-7ba2-4891-9514-6873f31d4b68",
      "name": "Set Search Inputs",
      "type": "n8n-nodes-base.set",
      "position": [
        -380,
        290
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "d44a911a-f8aa-4da1-9d52-cff5bb8ab206",
              "name": "searchQuery",
              "type": "string",
              "value": "dentists"
            },
            {
              "id": "cf052d3e-9499-4b73-b317-c470d12dd83f",
              "name": "location",
              "type": "string",
              "value": "Berlin Germany"
            },
            {
              "id": "7165ebef-96e5-4bdc-8bc0-9989aa8c1b49",
              "name": "maxResults",
              "type": "number",
              "value": 25
            },
            {
              "id": "29d0fae0-e299-4498-9007-d30aa5f26f71",
              "name": "spreadsheetName",
              "type": "string",
              "value": "Google Maps Leads"
            },
            {
              "id": "e7267ca7-c0be-412f-b5ed-b7147c624487",
              "name": "requestedAt",
              "type": "string",
              "value": "={{ new Date().toISOString() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "bdaef927-00c4-45ee-907e-f9804980aa7f",
      "name": "Scrapeer: Search and Enrich Leads",
      "type": "@scrapeer/n8n-nodes-scrapeer.scrapeer",
      "notes": "Select the saved Flow created from the Google Maps Leads template. Scrapeer searches Google Maps, deduplicates businesses by mapsUrl, and enriches each lead from its detail page.",
      "position": [
        40,
        290
      ],
      "parameters": {
        "resource": "flow",
        "operation": "runFlowAndWait",
        "projectId": "",
        "idempotencyKey": "",
        "inputVariables": "={{ JSON.stringify({ searchQuery: $json.searchQuery, location: $json.location, maxResults: $json.maxResults, spreadsheetName: $json.spreadsheetName }) }}",
        "timeoutSeconds": 900,
        "maxTotalCredits": 0,
        "pollIntervalSeconds": 10
      },
      "notesInFlow": true,
      "typeVersion": 1
    },
    {
      "id": "49b89bed-3aeb-409f-9da7-4df9ba74266b",
      "name": "Prepare Google Sheets Rows",
      "type": "n8n-nodes-base.code",
      "position": [
        520,
        290
      ],
      "parameters": {
        "jsCode": "const context = $('Set Search Inputs').first().json;\nconst run = $json.run;\nconst leads = run?.outputs?.enrichedGoogleMapsLeads;\n\nif (!Array.isArray(leads)) {\n  const status = run?.status ?? $json.status ?? 'unknown';\n  throw new Error(`Scrapeer Google Maps Leads Flow returned no enrichedGoogleMapsLeads array (status: ${status}).`);\n}\n\nfunction cleanText(value) {\n  return value === undefined || value === null ? '' : String(value).trim();\n}\n\nfunction sheetSafeText(value) {\n  const text = cleanText(value);\n  return /^[=+\\-@]/.test(text) ? `'${text}` : text;\n}\n\nfunction normalizeRating(value) {\n  const match = cleanText(value).replace(',', '.').match(/[0-9]+(?:[.][0-9]+)?/);\n  return match ? Number(match[0]) : '';\n}\n\nfunction normalizeReviewCount(value) {\n  const digits = cleanText(value).replace(/[^0-9]/g, '');\n  return digits ? Number(digits) : '';\n}\n\nconst scrapedAt = cleanText(run.finished_at) || cleanText(context.requestedAt) || new Date().toISOString();\n\nreturn leads.map((lead, index) => {\n  if (!lead || typeof lead !== 'object' || Array.isArray(lead)) {\n    throw new Error(`Scrapeer returned an invalid lead at index ${index}.`);\n  }\n\n  return {\n    json: {\n      scrapedAt,\n      searchQuery: cleanText(context.searchQuery),\n      location: cleanText(context.location),\n      name: sheetSafeText(lead.name),\n      category: sheetSafeText(lead.category),\n      rating: normalizeRating(lead.rating),\n      reviews: normalizeReviewCount(lead.reviewCount),\n      address: sheetSafeText(lead.address),\n      phone: sheetSafeText(lead.phone),\n      website: cleanText(lead.website),\n      googleMapsUrl: cleanText(lead.mapsUrl)\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "53fe1433-6c8a-4995-a235-61ea211995d6",
      "name": "GSheets: Append Leads",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        960,
        290
      ],
      "parameters": {
        "columns": {
          "value": {
            "Name": "={{ $json.name }}",
            "Phone": "={{ $json.phone }}",
            "Rating": "={{ $json.rating }}",
            "Address": "={{ $json.address }}",
            "Reviews": "={{ $json.reviews }}",
            "Website": "={{ $json.website }}",
            "Category": "={{ $json.category }}",
            "Location": "={{ $json.location }}",
            "Scraped At": "={{ $json.scrapedAt }}",
            "Search Query": "={{ $json.searchQuery }}",
            "Google Maps URL": "={{ $json.googleMapsUrl }}"
          },
          "schema": [
            {
              "id": "Scraped At",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Scraped At",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Search Query",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Search Query",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Location",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Location",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Category",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Category",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Rating",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Rating",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Reviews",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Reviews",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Address",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Address",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Phone",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Website",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Website",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Google Maps URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Google Maps URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Leads"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Choose your lead generation sheet"
        },
        "authentication": "serviceAccount"
      },
      "typeVersion": 4.7
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "d63b6a44-2c09-48c6-9944-5b1de76bb15a",
  "connections": {
    "Manual Test": {
      "main": [
        [
          {
            "node": "Set Search Inputs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily Schedule": {
      "main": [
        [
          {
            "node": "Set Search Inputs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Search Inputs": {
      "main": [
        [
          {
            "node": "Scrapeer: Search and Enrich Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Google Sheets Rows": {
      "main": [
        [
          {
            "node": "GSheets: Append Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrapeer: Search and Enrich Leads": {
      "main": [
        [
          {
            "node": "Prepare Google Sheets Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}