This workflow corresponds to n8n.io template #10473 — we link there as the canonical source.
This workflow follows the Agent → Gmail Tool 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": "7T8cybH4ocFzOOB7",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Automated BBB Lead Generation with BrowserAct",
"tags": [],
"nodes": [
{
"id": "312354c8-9ef1-47fc-9be1-684276476ace",
"name": "If",
"type": "n8n-nodes-base.if",
"notes": "This is the logic to check error you may change the logic according to your need ",
"position": [
224,
144
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "142abde8-01ae-4dae-9ad5-5493e7c72184",
"operator": {
"type": "number",
"operation": "notExists",
"singleValue": true
},
"leftValue": "={{ $json.error }}",
"rightValue": ""
},
{
"id": "49b4a0b5-c02d-405e-9810-73c9f764b53a",
"operator": {
"type": "string",
"operation": "notEquals"
},
"leftValue": "={{ $json.id }}",
"rightValue": "null"
}
]
}
},
"notesInFlow": true,
"typeVersion": 2.2
},
{
"id": "79264b3f-8164-448a-b763-3439ae122d2a",
"name": "Wait",
"type": "n8n-nodes-base.wait",
"position": [
512,
384
],
"parameters": {
"amount": 15
},
"typeVersion": 1.1
},
{
"id": "b61dd38b-1afc-4b69-90be-622d3b688c28",
"name": "AI Agent1",
"type": "@n8n/n8n-nodes-langchain.agent",
"notes": "This Agent can be perform to search , check duplicates , send email message , and append the data in the google sheet. \nThis instruction can be change according to your own requirements.",
"position": [
1424,
96
],
"parameters": {
"text": "=You are an automation assistant processing a SINGLE business lead.\n\n\n\nHere is the current business data you need to process:\n\n- Business Name: {{ $json.business_name }}\n\n- Email Address: {{ $json.email_address }}\n\n- Website: {{ $json.website_url }}\n\n\n\nYour Goal:\n\nProcess this specific business based on the rules below.\n\n\n\nStep 1: Check for Duplicates\n\n1. Call the \"read:sheet\" tool to get current sheet data.\n\n2. Check if the \"Business Name\" provided above exists in the 'business_name' column of the sheet.\n\n3. IF IT EXISTS:\n\n - Call the \"duplicate data (send:message)\" tool.\n\n - STOP processing.\n\n\n\nStep 2: Validate Email\n\n1. IF NO DUPLICATE FOUND: Check the \"Email Address\" provided above.\n\n2. Check the variable {{ $json.email_address }} against these strict rules:\n\n a. NOT EMPTY: The field must not be null, undefined, or an empty string (\"\").\n\n b. NO SPACES: The email string must not contain any whitespace characters.\n\n c. STRICT FORMAT: It must match this Regex exactly: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0- 9.-]+\\.[a-zA-Z]{2,}$/\n\n d. Suspicious Domain Check: Rejects emails ending in \"@aol.com\" or \"@hotmail.com\" (or other high-bounce providers if you wish).\n\n e. Gibberish Check: Rejects emails that look like random spam (e.g., \"123456@gmail.com\" or \"test@test.com\").\n\n3. IF INVALID (Fails any check above):\n\n - Call the \"append:sheet\" tool to log this business with status 'Pending - Invalid Email'.\n\n - STOP processing.\n\n\n\nStep 3: Send Outreach\n\n1. IF EMAIL IS VALID (Passes all checks):\n\n - Call the \"outreach email (send:message)\" tool.\n\n - Call the \"append:sheet\" tool to log this business with status 'Successful'.\n\n\n\nIMPORTANT RULES:\n\n- You are processing ONE item. Do not ask for a list.\n\n- Only execute ONE outcome (Duplicate, Invalid, or Success).",
"options": {
"systemMessage": "="
},
"promptType": "define"
},
"notesInFlow": true,
"typeVersion": 2.2
},
{
"id": "e217f12f-5668-48e2-a40d-3e6a30522d11",
"name": "Google Gemini Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
1152,
336
],
"parameters": {
"options": {}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "2001df14-7f5f-4c3c-8b7b-836370fdcbd3",
"name": "Run a workflow",
"type": "n8n-nodes-browseract.browserAct",
"notes": "Connect your BrowserAct account using your browseract api key in it.\nBrowseract is an no code tool used for scraping which we used for scraping business lead from BBB directories.",
"position": [
0,
240
],
"parameters": {
"templateId": "64933121971219894",
"workflowConfig": {
"value": {
"input-keyword": "Digital Marketing Agency",
"input-Datelimit": "5"
},
"schema": [
{
"id": "input-keyword",
"type": "string",
"display": true,
"removed": false,
"required": false,
"description": "If left blank, the default value defined in BrowserAct will be used.",
"displayName": "keyword",
"defaultMatch": true
},
{
"id": "input-Datelimit",
"type": "string",
"display": true,
"removed": false,
"required": false,
"description": "If left blank, the default value defined in BrowserAct will be used.",
"displayName": "Datelimit",
"defaultMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"input-keyword"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
}
},
"credentials": {
"browserActApi": {
"name": "<your credential>"
}
},
"notesInFlow": true,
"typeVersion": 1
},
{
"id": "6c011868-7ffe-4a39-939c-94615e653b3c",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"notes": "In this node only fetch the output.string from Browseract.",
"position": [
448,
-16
],
"parameters": {
"text": "=You are a data extraction assistant.\n\nYou will receive input that may contain JSON, text, or markdown. Your task is to extract the actual JSON array from the input and output a CLEAN JSON array.\n\nRules:\n\n1. Extract the JSON array from {{ $json.output.string }}.\n2. For each object in the array, output exactly these keys:\n - business_name\n - website_url\n - phone_number\n - email_address\n - rating\n3. If any field is missing, use an empty string (\"\").\n4. Your output MUST be a valid JSON array (NOT a string).\n5. Do NOT wrap the JSON in quotes.\n6. Do NOT output markdown, backticks, or explanations.\n7. Output ONLY the final JSON array.\n",
"options": {},
"promptType": "define"
},
"notesInFlow": true,
"typeVersion": 2.2
},
{
"id": "d9e0caf5-a05d-4eb8-a0a3-ee6b8d440619",
"name": "Google Gemini Chat Model2",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
528,
208
],
"parameters": {
"options": {}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "5b8f9a50-b3ba-4265-9983-2c8382371524",
"name": "get row's in sheet",
"type": "n8n-nodes-base.googleSheetsTool",
"notes": "this is the search sheet here logic should be change according to your own need or set it as it is.",
"position": [
1312,
336
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PxksaSGYYwNx_s1a_tYBwQ4FPsR1mqj24syeZcdbmOU/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1PxksaSGYYwNx_s1a_tYBwQ4FPsR1mqj24syeZcdbmOU",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PxksaSGYYwNx_s1a_tYBwQ4FPsR1mqj24syeZcdbmOU/edit?usp=drivesdk",
"cachedResultName": "lead for vapi"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"notesInFlow": true,
"typeVersion": 4.7
},
{
"id": "be8f442e-008b-4d39-99ac-29f89f8aa779",
"name": "append row in sheet",
"type": "n8n-nodes-base.googleSheetsTool",
"notes": "this node append all the data in the google sheet.",
"position": [
1760,
336
],
"parameters": {
"columns": {
"value": {
"rating": "={{ $('Loop Over Items').item.json.rating }}",
"email_sent": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('email_sent', `In this only save whethere Pending (invalid email) or successfully sent based on the email_address valid or not.`, 'string') }}",
"website_url": "={{ $('Loop Over Items').item.json.website_url }}",
"phone_number": "={{ $('Loop Over Items').item.json.phone_number }}",
"business_name": "={{ $('Loop Over Items').item.json.business_name }}",
"email_address": "={{ $('Loop Over Items').item.json.email_address }}"
},
"schema": [
{
"id": "business_name",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "business_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "phone_number",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "phone_number",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "email_address",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "email_address",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "website_url",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "website_url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "rating",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "rating",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "email_sent",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "email_sent",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PxksaSGYYwNx_s1a_tYBwQ4FPsR1mqj24syeZcdbmOU/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1PxksaSGYYwNx_s1a_tYBwQ4FPsR1mqj24syeZcdbmOU",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1PxksaSGYYwNx_s1a_tYBwQ4FPsR1mqj24syeZcdbmOU/edit?usp=drivesdk",
"cachedResultName": "lead for vapi"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "efdcbd10-0fb7-4209-8eb3-d8ca3570ee64",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-224,
240
],
"parameters": {
"rule": {
"interval": [
{}
]
}
},
"typeVersion": 1.2
},
{
"id": "9cfb5fbf-e5c7-450d-b7c1-9814ae33c1cf",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-944,
-144
],
"parameters": {
"width": 576,
"height": 400,
"content": "This n8n template automates business lead scraping using BrowserAct, cleans the data with AI Agents, checks duplicates, sends outreach emails via Gmail, and stores results in Google Sheets.\n\n## How it works\n\nThe workflow starts automatically with a Schedule Trigger.\n\nBrowserAct collects business details based on keywords and location.\n\nAn If node checks if the scraping output is valid.\n\nAI Agent 1 (Gemini) extracts clean business data into structured JSON.\n\nA Code node formats and parses the AI output.\n\nGoogle Sheets is used to read existing rows and identify duplicates.\n\nAI Agent 2 (Gemini) decides: duplicate, invalid email, or send outreach email.\n\nGmail Node sends personalized emails to valid leads.\n\nGoogle Sheets appends each processed business with the final status.\n\nA Wait node controls the sending speed and limits email volume."
},
"typeVersion": 1
},
{
"id": "9857ea05-b7e7-4b9a-9726-124123393669",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-944,
288
],
"parameters": {
"width": 576,
"height": 304,
"content": "## How to use it\n\nCreate the lead_scraping workflow inside your BrowserAct account.\n\nAdd your BrowserAct API token to the BrowserAct node inside this workflow.\n\nReplace the default workflow_id with your actual BrowserAct workflow ID.\n\nConnect your Google Gemini API credentials to both AI Agent nodes.\n\nConnect your Google Sheets account and select the sheet where the leads will be stored.\n\nConnect your Gmail account to the Gmail node for sending outreach emails."
},
"typeVersion": 1
},
{
"id": "bc60bd56-9561-4f64-a839-86b679599ddf",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-336,
-144
],
"parameters": {
"color": 6,
"width": 1104,
"height": 736,
"content": "## Data Scrap & Structured"
},
"typeVersion": 1
},
{
"id": "9a5bc4a8-cec4-4610-aa9e-a7416f1de172",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
784,
-144
],
"parameters": {
"color": 6,
"width": 1280,
"height": 736,
"content": "## Data search, append, email, update\n"
},
"typeVersion": 1
},
{
"id": "ac8dc50a-a1c5-42fa-b8ed-1aa59ab62c7e",
"name": "Code in JavaScript",
"type": "n8n-nodes-base.code",
"notes": "This code is responsible to convert the string data into proper structure array format. You can write the code according to your need.",
"position": [
832,
64
],
"parameters": {
"jsCode": "// Get raw AI output\nlet raw = $json.output || '';\n\n// Clean JSON\nraw = raw.replace(/```json|```/g, '').trim();\nraw = raw.replace(/\\\\n/g, '').replace(/\\\\\"/g, '\"').trim();\n\n// Extract JSON array only\nconst firstBracket = raw.indexOf('[');\nconst lastBracket = raw.lastIndexOf(']');\nif (firstBracket !== -1 && lastBracket !== -1) {\n raw = raw.substring(firstBracket, lastBracket + 1);\n}\n\n// Parse JSON\nlet data = [];\ntry {\n data = JSON.parse(raw);\n} catch (err) {\n return [{ json: { error: \"Invalid JSON\", details: err.message, raw } }];\n}\n\n// Ensure it's an array\nif (!Array.isArray(data)) data = [data];\n\n// \u2705 Split into individual items\nreturn data.map(item => ({ json: item }));\n"
},
"notesInFlow": true,
"typeVersion": 2
},
{
"id": "37710032-2b3a-4bf3-b6ce-4e907aca9e4c",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"notes": "Loops execute one by one all businesses.",
"position": [
1056,
80
],
"parameters": {
"options": {}
},
"notesInFlow": true,
"typeVersion": 3
},
{
"id": "84de1f68-5233-412d-83a6-7466b5b4cc12",
"name": "duplicate data",
"type": "n8n-nodes-base.gmailTool",
"notes": "This not neccessary node you can remove if you want else it only send a message when they found any duplicate data.",
"position": [
1456,
336
],
"parameters": {
"sendTo": "user@example.com",
"message": "this data is already available in the sheet",
"options": {},
"subject": "duplicate lead found"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "085a9f00-c7d8-4a31-9acc-6614ba8b6d87",
"name": "outreach email",
"type": "n8n-nodes-base.gmailTool",
"notes": "This node send email message to the busniess email_Address.",
"position": [
1600,
336
],
"parameters": {
"sendTo": "={{ $('Loop Over Items').item.json.email_address }}",
"message": "=Hi {{ $('Loop Over Items').item.json.business_name }}, I'm [Bakir Ali], reaching out because I believe we can significantly help {{ $('Loop Over Items').item.json.business_name }} thrive even further. Managing social media and generating quality leads for clients can be incredibly time-consuming and complex. Our automation solution is designed specifically for digital marketing agencies like yours to: - Automate repetitive social media tasks: Freeing up your team for more strategic work. - Supercharge lead generation: Ensuring a consistent flow of qualified leads. - Reduce complexity & boost results: Achieve more with less manual effort. We help agencies save valuable time, cut down on complex tasks, and deliver better results for their clients. Would you be open to a quick 10-15 minute chat next week to see how this could specifically benefit for businesses like your {{ $('Loop Over Items').item.json.business_name }}? Best regards, Bakir Ali AI Automation Specialist",
"options": {},
"subject": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Subject', ``, 'string') }}",
"emailType": "text"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "dff8c0d0-9e45-4e39-993b-e693e5eb4da5",
"connections": {
"If": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait",
"type": "main",
"index": 0
}
]
]
},
"Wait": {
"main": [
[
{
"node": "Run a workflow",
"type": "main",
"index": 0
}
]
]
},
"AI Agent": {
"main": [
[
{
"node": "Code in JavaScript",
"type": "main",
"index": 0
}
]
]
},
"AI Agent1": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Run a workflow": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"duplicate data": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"outreach email": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "AI Agent1",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Run a workflow",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"get row's in sheet": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"append row in sheet": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"Google Gemini Chat Model1": {
"ai_languageModel": [
[
{
"node": "AI Agent1",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Google Gemini Chat Model2": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"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.
browserActApigmailOAuth2googlePalmApigoogleSheetsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automates business data extraction, duplicate checking, and email outreach using BrowserAct, Google Sheets, Gmail, and Google Gemini AI — all inside n8n.
Source: https://n8n.io/workflows/10473/ — 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 template is for clinics, hospitals, care teams, and telemedicine providers who need a structured, automated system for post-surgery follow-up. It helps reduce manual workload while ensuring every
Categories: Lead Generation, Business Automation, AI
Telegram Trigger receives incoming messages (text, voice, photo, document). Switch routes by message type to appropriate processors: Text → forwarded as-is. Voice → downloaded and sent to Transcribe a
Transform your Telegram messenger into a powerful, multi-modal personal or team assistant. This n8n workflow creates an intelligent agent that can understand text, voice, images, and documents, and ta
This workflow is an AI-powered Dental Appointment Assistant that automates appointment booking, rescheduling, and cancellations through Telegram or a Webhook. It uses intelligent agents to understand