{
  "id": "peAcf7qB5sEcwPt4",
  "meta": {
    "aiBuilderAssisted": true
  },
  "name": "GMB Lead Finder \u2014 Scrape Google Business Reviews by Type & Location",
  "tags": [],
  "nodes": [
    {
      "id": "e7448702-e07a-46f7-9996-98c387ce5628",
      "name": "GMB Lead Form",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -192,
        176
      ],
      "parameters": {
        "options": {},
        "formTitle": "GMB Lead Finder",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Business type",
              "placeholder": "e.g. plumber, roofer, dentist"
            },
            {
              "fieldLabel": "Location",
              "placeholder": "e.g. Miami, FL"
            }
          ]
        },
        "formDescription": "Enter a business category and city to find local businesses with 1-star Google reviews."
      },
      "typeVersion": 2.5
    },
    {
      "id": "0e7a8692-b503-4219-b989-bb397ba7bbee",
      "name": "Build Search Query",
      "type": "n8n-nodes-base.set",
      "position": [
        80,
        176
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "2f71be8d-9e7f-47f5-86ff-b9f8d91e475c",
              "name": "search_query",
              "type": "string",
              "value": "={{ $json[\"Business type\"] + \" in \" + $json[\"Location\"] }}"
            },
            {
              "id": "ac9da345-560b-4427-a8fc-9050b3cbb0a1",
              "name": "location",
              "type": "string",
              "value": "={{ $json.Location }}"
            },
            {
              "id": "cfg-001-sheet-id",
              "name": "googleSheetId",
              "type": "string",
              "value": ""
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f1f637b0-19c5-499a-861e-e1d0690352b7",
      "name": "Start Apify Scraper Run",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        304,
        176
      ],
      "parameters": {
        "url": "https://api.apify.com/v2/acts/nwua9Gu5YrADL7ZDj/runs",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n    \"searchStringsArray\": [\"={{ $('Build Search Query').item.json.search_query }}\"],\n    \"includeWebResults\": false,\n    \"language\": \"en\",\n    \"locationQuery\": \"={{ $('Build Search Query').item.json.location }}\",\n    \"maxCrawledPlacesPerSearch\": 10,\n    \"scrapeContacts\": true,\n    \"maxImages\": 0,\n    \"maxReviews\": 200,\n    \"maximumLeadsEnrichmentRecords\": 0,\n    \"reviewsOrigin\": \"google\",\n    \"reviewsSort\": \"lowestRanking\",\n    \"scrapeDirectories\": false,\n    \"scrapeImageAuthors\": false,\n    \"scrapePlaceDetailPage\": false,\n    \"scrapeReviewsPersonalData\": true,\n    \"scrapeSocialMediaProfiles\": {\n        \"facebooks\": false,\n        \"instagrams\": false,\n        \"tiktoks\": false,\n        \"twitters\": false,\n        \"youtubes\": false\n    },\n    \"scrapeTableReservationProvider\": false,\n    \"skipClosedPlaces\": false\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "418c218d-e66c-4913-94db-62471198a1a2",
      "name": "Poll Apify Run Status",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 5,
      "position": [
        528,
        176
      ],
      "parameters": {
        "url": "=https://api.apify.com/v2/actor-runs/{{$json.data.id}}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.4,
      "waitBetweenTries": 2000
    },
    {
      "id": "afb84aa7-3ce6-477b-9158-9aedc62d60a6",
      "name": "Run Completed?",
      "type": "n8n-nodes-base.if",
      "position": [
        752,
        96
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "1cdf6e3b-b36e-415f-a437-32fa246b713b",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.data.status }}",
              "rightValue": "RUNNING"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "59c83d39-75ab-44c7-9076-90ee1d70672b",
      "name": "Wait Before Retry",
      "type": "n8n-nodes-base.wait",
      "position": [
        800,
        304
      ],
      "parameters": {
        "amount": 10
      },
      "typeVersion": 1.1
    },
    {
      "id": "16a248cb-b776-4925-974c-d7f664267fb5",
      "name": "Fetch Scraped Dataset",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 5,
      "position": [
        1232,
        144
      ],
      "parameters": {
        "url": "=https://api.apify.com/v2/datasets/{{$json.data.defaultDatasetId}}/items?clean=true&format=json",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.4,
      "waitBetweenTries": 2000
    },
    {
      "id": "2a46be1a-325e-434f-a1e1-03c31eacf55e",
      "name": "Has 1-Star Reviews?",
      "type": "n8n-nodes-base.if",
      "position": [
        1456,
        144
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "2c5c36a7-50ec-40ca-8b80-3396c2bc70c8",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.reviewsDistribution.oneStar }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "00f171aa-e8a8-48a0-bd6e-462c07c5df49",
      "name": "Create Tab for This Run",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1680,
        144
      ],
      "parameters": {
        "title": "={{ $('Build Search Query').item.json.search_query + ' - ' + $now.format('yyyy-MM-dd HH:mm') }}",
        "options": {},
        "operation": "create",
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Build Search Query').item.json.googleSheetId }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 4.7
    },
    {
      "id": "1c65addc-7b4e-437f-b668-59cb9e64eae4",
      "name": "Transform & Format GMB Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1904,
        144
      ],
      "parameters": {
        "jsCode": "const allGMB = $('Has 1-Star Reviews?').all()\nconst result = []\n\nfor (const gmb of allGMB) {\n  const reviews = gmb.json.reviews || []\n  const oneStar = gmb.json.reviewsDistribution?.oneStar || 0\n  let reviewWithImage = ''\n\n  for (let i = 0; i < Math.min(reviews.length, 10); i++) {\n    const rev = reviews[i]\n    if (rev && Array.isArray(rev.reviewImageUrls) && rev.reviewImageUrls.length > 0) {\n      reviewWithImage = rev.reviewUrl || ''\n      break\n    }\n  }\n\n  result.push({\n    json: {\n      'Business Name': gmb.json.title || '',\n      'GMB URL': gmb.json.url || '',\n      'City[Location]': gmb.json.address || '',\n      'Phone Number': gmb.json.phone ? `(${String(gmb.json.phone)})` : '',\n      'Alternative Number': gmb.json.phoneUnformatted || '',\n      'Business Email': (gmb.json.emails && gmb.json.emails.length > 0) ? gmb.json.emails[0] : '',\n      'Negative review URLs': reviews[0]?.reviewUrl || '',\n      'Negative review URL With Image': reviewWithImage,\n      'One Star Review Count': oneStar\n    }\n  })\n}\n\nreturn result"
      },
      "typeVersion": 2
    },
    {
      "id": "039c4bc7-a433-4caa-9079-a95bdb36144c",
      "name": "Write Results to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2128,
        144
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [
            {
              "id": "Business Name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Business Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "GMB URL",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "GMB URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "City[Location]",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "City[Location]",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Phone Number",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Phone Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Alternative Number",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Alternative Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Business Email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Business Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Negative review URLs",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Negative review URLs",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Negative review URL With Image",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Negative review URL With Image",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "One Star Review Count",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "One Star Review Count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [
            "spreadsheetId"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Create Tab for This Run').item.json.title }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Build Search Query').item.json.googleSheetId }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "typeVersion": 4.7
    },
    {
      "id": "c682e432-9f00-4ffe-87cd-bb8f6c203046",
      "name": "Sticky Note \u2013 Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -848,
        -240
      ],
      "parameters": {
        "width": 504,
        "height": 684,
        "content": "## GMB Lead Finder\n\nFinds local businesses with 1-star Google reviews \u2014 ideal for reputation management outreach.\n\n### How it works\n1. User submits a business type (e.g. \"dentist\") and city via the web form.\n2. Workflow builds a search query and triggers an Apify Google Maps scraper.\n3. Apify runs async \u2014 polls every 10 s until the job finishes.\n4. Only businesses with at least one 1-star review are kept.\n5. A new tab is created in Google Sheets and the leads are written there.\n\n### Setup steps\n- [ ] In Build Search Query, paste your Google Sheet ID into the googleSheetId field.\n- [ ] Add your Apify API token as HTTP Header Auth (header: Authorization, value: Bearer YOUR_TOKEN).\n- [ ] Connect your Google Sheets OAuth2 credential to the two Sheets nodes.\n- [ ] Activate the workflow to get the form URL.\n\n### Customization\n- Increase maxCrawledPlacesPerSearch to scrape more businesses.\n- Increase maxReviews to collect more review data."
      },
      "typeVersion": 1
    },
    {
      "id": "affb9671-e9de-41b6-a03a-1d908c7a7b1f",
      "name": "Sticky Note \u2013 Apify Loop",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -240,
        -240
      ],
      "parameters": {
        "color": 3,
        "width": 424,
        "height": 162,
        "content": "## Step 1  Input & Query Builder\n\nUser fills the form with a business type and location. The Set node combines them into a search string (e.g. \"plumber in Miami, FL\") and stores the Google Sheet ID for use downstream."
      },
      "typeVersion": 1
    },
    {
      "id": "a1b2c3d4-e5f6-4890-abcd-ef1234567890",
      "name": "Run Succeeded?",
      "type": "n8n-nodes-base.if",
      "position": [
        1008,
        192
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "run-succeeded-condition-01",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.data.status }}",
              "rightValue": "SUCCEEDED"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "b2c3d4e5-f6a7-4901-bcde-f12345678901",
      "name": "Stop and Error",
      "type": "n8n-nodes-base.stopAndError",
      "position": [
        1280,
        416
      ],
      "parameters": {
        "errorMessage": "=Apify run failed with status: {{ $json.data.status }}"
      },
      "typeVersion": 1
    },
    {
      "id": "c6c117d3-e4e9-4c96-8e43-573a286f0ae3",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        288,
        -256
      ],
      "parameters": {
        "color": 4,
        "width": 576,
        "height": 288,
        "content": "## Step 2  Apify Scraper & Polling Loop\n\nApify runs asynchronously. The workflow starts the scrape job, then polls every 10 s until the status is no longer RUNNING.\n- \u2705 SUCCEEDED \u2192 fetch the dataset and continue\n- \u274c FAILED / ABORTED \u2192 Stop and Error halts the execution\n\nBoth HTTP nodes retry up to 5\u00d7 on network failure."
      },
      "typeVersion": 1
    },
    {
      "id": "373c7137-476c-446b-9bc3-6e91f8369d91",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1520,
        -240
      ],
      "parameters": {
        "color": 6,
        "width": 736,
        "height": 256,
        "content": "## Step 3  Filter, Transform & Export\n\nOnly businesses with at least one 1-star review pass through. Key fields  name, phone, email, GMB URL, review links  are extracted and written to a new timestamped tab in Google Sheets."
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "settings": {
    "binaryMode": "separate",
    "callerPolicy": "workflowsFromSameOwner",
    "timeSavedMode": "fixed",
    "availableInMCP": true,
    "executionOrder": "v1"
  },
  "versionId": "0b6133bf-f118-492d-aa63-b2b92929fe5c",
  "connections": {
    "GMB Lead Form": {
      "main": [
        [
          {
            "node": "Build Search Query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run Completed?": {
      "main": [
        [
          {
            "node": "Run Succeeded?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait Before Retry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run Succeeded?": {
      "main": [
        [
          {
            "node": "Fetch Scraped Dataset",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Stop and Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait Before Retry": {
      "main": [
        [
          {
            "node": "Poll Apify Run Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Search Query": {
      "main": [
        [
          {
            "node": "Start Apify Scraper Run",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has 1-Star Reviews?": {
      "main": [
        [
          {
            "node": "Create Tab for This Run",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Scraped Dataset": {
      "main": [
        [
          {
            "node": "Has 1-Star Reviews?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Poll Apify Run Status": {
      "main": [
        [
          {
            "node": "Run Completed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Tab for This Run": {
      "main": [
        [
          {
            "node": "Transform & Format GMB Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Start Apify Scraper Run": {
      "main": [
        [
          {
            "node": "Poll Apify Run Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transform & Format GMB Data": {
      "main": [
        [
          {
            "node": "Write Results to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}