This workflow corresponds to n8n.io template #9219 — we link there as the canonical source.
This workflow follows the Apifyn8N Nodes Apify → 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 →
{
"id": "6ZDejfbyr1msa2zv",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Automate Sales Outreach with LinkedIn Job Signals, Apify, Apollo.io & Google Gemini",
"tags": [],
"nodes": [
{
"id": "0fd7b446-8b69-4fb4-b79e-f69fbe4082ab",
"name": "Update Sheet with Email",
"type": "n8n-nodes-base.googleSheets",
"position": [
2560,
1008
],
"parameters": {
"columns": {
"value": {
"Email": "={{ $('Filter for Batching').item.json.Email }}",
"Subject": "={{ $json.output.subject }}",
"Email Body": "={{ $json.output.email_body }}"
},
"schema": [
{
"id": "First Name",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "First Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Last Name",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Last Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Occupation",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Occupation",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Company",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Company",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LinkedIn Url",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "LinkedIn Url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Company LinkedIn Url",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Company LinkedIn Url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Company URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Company URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Location",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Location",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Domain",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Domain",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Company Description",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Company Description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Employee Count",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Employee Count",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Job Title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Job Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Subject",
"type": "string",
"display": true,
"required": false,
"displayName": "Subject",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email Body",
"type": "string",
"display": true,
"required": false,
"displayName": "Email Body",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "string",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_AWS_SECRET_KEY_HERE_gdo/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "YOUR_AWS_SECRET_KEY_HERE_gdo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_AWS_SECRET_KEY_HERE_gdo/edit?usp=drivesdk",
"cachedResultName": "LinkedIn Lead Gen"
}
},
"typeVersion": 4
},
{
"id": "12d544fc-86d7-4cbf-9be7-ed6d4730dbdf",
"name": "Google Gemini Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
1936,
1376
],
"parameters": {
"options": {}
},
"typeVersion": 1
},
{
"id": "78b63764-9948-40ca-be63-f188ff8faeba",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
2496,
1376
],
"parameters": {
"jsonSchemaExample": "{\n \"subject\": \"A short, catchy, question-based subject line\",\n \"email_body\": \"The full email body, 100-120 words, without any salutation or sign-off.\"\n}"
},
"typeVersion": 1.3
},
{
"id": "6e685361-565d-4dc6-9149-a6c2b23fe2c3",
"name": "When clicking \u2018Execute workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-816,
160
],
"parameters": {},
"typeVersion": 1
},
{
"id": "9af7695c-fb5d-4a23-b7e3-8d26a821b4d1",
"name": "Remove Duplicates",
"type": "n8n-nodes-base.removeDuplicates",
"position": [
-768,
496
],
"parameters": {
"compare": "selectedFields",
"options": {
"removeOtherFields": false,
"disableDotNotation": false
},
"fieldsToCompare": "companyName"
},
"typeVersion": 2
},
{
"id": "c1348833-1b28-4270-ae53-4dbcfc93251e",
"name": "Run the LinkedIn Job Scraper",
"type": "@apify/n8n-nodes-apify.apify",
"position": [
-432,
96
],
"parameters": {
"memory": 4096,
"actorId": {
"__rl": true,
"mode": "list",
"value": "hKByXkMQaC5Qt9UMN",
"cachedResultUrl": "https://console.apify.com/actors/hKByXkMQaC5Qt9UMN/input",
"cachedResultName": "Linkedin Jobs Scraper - PPR (curious_coder/linkedin-jobs-scraper)"
},
"timeout": {},
"customBody": "{\n \"count\": 100,\n \"scrapeCompany\": true,\n \"urls\": [\n \"https://www.linkedin.com/jobs/search-results/?distance=25&f_TPR=r86400&geoId=103644278&keywords=ML%20Engineer&origin=SEMANTIC_SEARCH_HISTORY\"\n ]\n}"
},
"typeVersion": 1
},
{
"id": "5e36853c-5e15-42ac-9c7e-95c60aadf9da",
"name": "Get dataset Items",
"type": "@apify/n8n-nodes-apify.apify",
"position": [
96,
160
],
"parameters": {
"limit": 110,
"offset": {},
"resource": "Datasets",
"datasetId": "={{ $json.defaultDatasetId }}"
},
"typeVersion": 1
},
{
"id": "92470dd9-7f01-4795-b36a-8d1553a12e80",
"name": "Checks Company Size < 250",
"type": "n8n-nodes-base.if",
"position": [
592,
208
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "ed72c7e6-2a1f-4c8e-b87c-7ab53ea8f356",
"operator": {
"type": "number",
"operation": "lt"
},
"leftValue": "={{ $json.companyEmployeesCount }}",
"rightValue": 250
}
]
}
},
"typeVersion": 2.2
},
{
"id": "9469d083-1393-4661-bc1a-2626be76b3af",
"name": "Removes HR Related Industry",
"type": "n8n-nodes-base.if",
"position": [
-400,
496
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "cd695047-a0f4-4058-b83b-339c5fe77a9c",
"operator": {
"type": "string",
"operation": "notContains"
},
"leftValue": "={{ $json.industries }}",
"rightValue": "Human Resources"
},
{
"id": "7b9d94db-da9c-4b94-8961-0827f5175f9c",
"operator": {
"type": "string",
"operation": "notContains"
},
"leftValue": "={{ $json.industries }}",
"rightValue": "Staffing and Recruiting"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "13ccb5b9-221b-4be6-ba7c-02c53205fc63",
"name": "Prepare Final Company Details",
"type": "n8n-nodes-base.code",
"position": [
112,
496
],
"parameters": {
"jsCode": "// n8n Function Node\n// Keep only required fields + extract clean domain from companyWebsite\n// Wrap output in \"company\" wrapper\n\nreturn items.map(item => {\n const data = item.json;\n\n let domain = null;\n if (data.companyWebsite) {\n let website = data.companyWebsite.trim();\n\n // If no protocol, prepend http://\n if (!/^https?:\\/\\//i.test(website)) {\n website = \"http://\" + website;\n }\n\n try {\n const parsedUrl = new URL(website);\n domain = parsedUrl.hostname.replace(/^www\\./, \"\"); // remove \"www.\"\n } catch (err) {\n // Fallback: strip query/hash manually\n domain = website\n .replace(/^(https?:\\/\\/)?(www\\.)?/, \"\")\n .split(/[/?#]/)[0]; // take only domain part\n }\n }\n\n return {\n json: {\n company: { // \ud83d\udc48 wrapper added\n companyName: data.companyName || null,\n companyLinkedInUrl: data.companyLinkedInUrl || data.companyLinkedinUrl || null,\n companyWebsite: data.companyWebsite || null,\n industries: data.industries || null,\n location: data.location || null,\n employeeCount: data.companyEmployeesCount || null,\n jobTitle: data.jobTitle || data.title || null,\n companyDescription: data.companyDescription || null,\n domain: domain\n }\n }\n };\n});\n"
},
"typeVersion": 2
},
{
"id": "43d308cf-516a-4acf-8b77-f20a3947f0cb",
"name": "Checks Domain Existence",
"type": "n8n-nodes-base.if",
"position": [
-800,
816
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "8f1130d1-8082-48a4-9f97-a05df2e6f725",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.company.domain }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "c25ec326-deb9-490e-97ab-ebe3521e41a0",
"name": "Apollo Get Targeted Personnel",
"type": "n8n-nodes-base.httpRequest",
"position": [
-1168,
1312
],
"parameters": {
"url": "https://api.apollo.io/api/v1/people/search",
"method": "POST",
"options": {},
"jsonBody": "={\n \"q_organization_domains_list\": [\"{{ $json.company.domain }}\"],\n \"person_seniorities\": [\"vp\", \"head\", \"director\", \"founder\", \"c-suite\", \"lead\"],\n \"person_titles\": [\n \"engineering\",\n \"technology\",\n \"product\",\n \"operations\",\n \"infrastructure\",\n \"devops\",\n \"data science\",\n \"machine learning\",\n \"cloud\"\n ],\n \"pagination\": { \"page\": 1, \"per_page\": 2 }\n}\n",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"typeVersion": 4.2
},
{
"id": "b42ec2f9-f178-49e3-aaf8-026fb1b3b360",
"name": "Apollo Email Finder",
"type": "n8n-nodes-base.httpRequest",
"position": [
-496,
1648
],
"parameters": {
"url": "https://api.apollo.io/v1/people/match",
"method": "POST",
"options": {},
"jsonBody": "={\n \"id\": \"{{ $json.person.personId }}\"\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"typeVersion": 4.2
},
{
"id": "dbd59767-6054-4a77-b097-73b537b7404d",
"name": "Sanitising Email Details",
"type": "n8n-nodes-base.code",
"position": [
16,
1648
],
"parameters": {
"jsCode": "// Extract only person.id + email\nreturn items.map(item => {\n return {\n json: {\n email: { // \ud83d\udc48 wrapped object\n id: item.json.person?.id || null,\n email: item.json.person?.email || null\n }\n }\n };\n});\n"
},
"typeVersion": 2
},
{
"id": "c2d53522-21bb-4d04-b3f5-f6c935356c9a",
"name": "Structuring Complete Details of Person",
"type": "n8n-nodes-base.code",
"position": [
816,
896
],
"parameters": {
"jsCode": "// N8N JavaScript Code Node - Clean Data Merging (No Debug)\n// Mapping Logic:\n// - person.personId <-> email.id (one-to-one, unique)\n// - person.companyName <-> company.companyName (many-to-one, multiple persons per company)\n\n// Get all input items\nconst allItems = $input.all();\n\n// Step 1: Build email lookup by personId (one-to-one mapping)\nconst emailMap = {};\nallItems.forEach(item => {\n const jsonData = item.json || {};\n if (jsonData.email && jsonData.email.id) {\n emailMap[jsonData.email.id] = jsonData.email.email;\n }\n});\n\n// Step 2: Build company lookup by companyName (many-to-one mapping)\nconst companyMap = {};\nallItems.forEach(item => {\n const jsonData = item.json || {};\n if (jsonData.company && jsonData.company.companyName) {\n companyMap[jsonData.company.companyName] = jsonData.company;\n }\n});\n\n// Step 3: Merge person with email + company info\nconst outputItems = [];\n\nallItems.forEach(item => {\n const jsonData = item.json || {};\n if (!jsonData.person) return;\n \n const person = jsonData.person;\n const personId = person.personId;\n const companyName = person.companyName;\n \n // Get email from emailMap (unique per person)\n const email = emailMap[personId] || null;\n \n // Get company info from companyMap (same for all persons at this company)\n const companyInfo = companyMap[companyName] || {};\n \n // Create merged record\n const mergedItem = {\n json: {\n ...person, // Spread all person fields\n email: email,\n companyDescription: companyInfo.companyDescription || null,\n jobTitle: companyInfo.jobTitle || null,\n employeeCount: companyInfo.employeeCount || null\n }\n };\n \n outputItems.push(mergedItem);\n});\n\n// Return the merged results\nreturn outputItems;"
},
"typeVersion": 2
},
{
"id": "326bb4c6-ce73-4e76-9576-685319d00b1e",
"name": "Adding Leads to Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
1040,
560
],
"parameters": {
"columns": {
"value": {
"Email": "={{ $json.email }}",
"Domain": "={{ $json.primaryDomain }}",
"Company": "={{ $json.companyName }}",
"Location": "={{ $json.city }}, {{ $json.country }}",
"Job Title": "={{ $json.jobTitle }}",
"Last Name": "={{ $json.lastName }}",
"First Name": "={{ $json.firstName }}",
"Occupation": "={{ $json.title }}",
"Company URL": "={{ $json.companyWebsite }}",
"LinkedIn Url": "={{ $json.personLinkedInUrl }}",
"Employee Count": "={{ $json.employeeCount }}",
"Company Description": "={{ $json.companyDescription }}",
"Company LinkedIn Url": "={{ $json.companyLinkedInUrl }}"
},
"schema": [
{
"id": "First Name",
"type": "string",
"display": true,
"required": false,
"displayName": "First Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Last Name",
"type": "string",
"display": true,
"required": false,
"displayName": "Last Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Occupation",
"type": "string",
"display": true,
"required": false,
"displayName": "Occupation",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Company",
"type": "string",
"display": true,
"required": false,
"displayName": "Company",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LinkedIn Url",
"type": "string",
"display": true,
"required": false,
"displayName": "LinkedIn Url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Company LinkedIn Url",
"type": "string",
"display": true,
"required": false,
"displayName": "Company LinkedIn Url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Company URL",
"type": "string",
"display": true,
"required": false,
"displayName": "Company URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Location",
"type": "string",
"display": true,
"required": false,
"displayName": "Location",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Domain",
"type": "string",
"display": true,
"required": false,
"displayName": "Domain",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email",
"type": "string",
"display": true,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Company Description",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Company Description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Employee Count",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Employee Count",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Job Title",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Job Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Subject",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Subject",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email Body",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Email Body",
"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/YOUR_AWS_SECRET_KEY_HERE_gdo/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "YOUR_AWS_SECRET_KEY_HERE_gdo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_AWS_SECRET_KEY_HERE_gdo/edit?usp=drivesdk",
"cachedResultName": "LinkedIn Lead Gen"
}
},
"typeVersion": 4.6
},
{
"id": "636f4815-dae0-4628-aa65-775781c405b5",
"name": "Fetching Leads Data",
"type": "n8n-nodes-base.googleSheets",
"position": [
1488,
560
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_AWS_SECRET_KEY_HERE_gdo/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "YOUR_AWS_SECRET_KEY_HERE_gdo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_AWS_SECRET_KEY_HERE_gdo/edit?usp=drivesdk",
"cachedResultName": "LinkedIn Lead Gen"
}
},
"typeVersion": 4
},
{
"id": "bb071500-09fa-492c-a64c-20fdd384e42a",
"name": "Validates Email Id and Email Content",
"type": "n8n-nodes-base.if",
"position": [
2160,
576
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "0640b75d-662e-4625-a038-92c099b79f25",
"operator": {
"type": "string",
"operation": "empty",
"singleValue": true
},
"leftValue": "={{ $json.Subject }}",
"rightValue": ""
},
{
"id": "6d30f170-03fd-4e89-9a56-ab87e8c7c01a",
"operator": {
"type": "string",
"operation": "empty",
"singleValue": true
},
"leftValue": "={{ $json[\"Email Body\"] }}",
"rightValue": ""
},
{
"id": "81d61ac3-f195-4516-8259-331f7190a0c3",
"operator": {
"type": "string",
"operation": "contains"
},
"leftValue": "={{ $json.Email }}",
"rightValue": "@"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "012dd6c0-612d-4bbb-b690-43282abc2df0",
"name": "Lead Email Generator",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
2032,
1008
],
"parameters": {
"text": "=Act as an expert B2B copywriter specializing in cold outreach for tech recruitment services.\n\n\nYour task is to write a personalized, friendly, and professional cold email. The goal is to get the attention of a busy executive by offering a clear solution to their current hiring needs.\n\n\nBACKGROUND & CONTEXT:\n\nOur Service: We provide pre-vetted, skilled remote tech talent (AI/ML Engineers, DevOps, etc.).\n\nTarget Company: US-based, under 250 employees.\n\nTarget Persona: CEO, CTO, Head of Engineering, VP of Operations.\n\nTrigger Event: The target company is actively hiring for a specific tech role.\n\nKey Value Proposition:\n\nSave significant time in the hiring process.\n\nSave 30-40% on budget compared to a direct, in-house hire.\n\n\nINPUT VARIABLES (You will use these to personalize the email):\n\n{{ $json.Company }}: The name of the company.\n\n{{ $json['Job Title'] }}: The specific job title they are hiring for (e.g., \"AI Engineer\").\n\n{{ $json.Occupation }}: The job title of the person I'm emailing (e.g., \"CTO\").\n\n\nINSTRUCTIONS & CONSTRAINTS:\n\n\n1. Subject Line:\n\nGenerate catchy subject line.\n\nEach subject line must be 7-8 words maximum.\n\nThey should be intriguing and directly related to their hiring needs. Examples: \"Your AI Engineer role,\" \"An idea for your engineering team,\" \"Filling your {{ $json['Job Title'] }} role.\"\n\n\n2. Email Body:\n\nWrite the email body only. Do not include a salutation like \"Hi {{ $json['First Name'] }}\".\n\nThe email must start with the exact phrase: \"Saw that {{ $json.Company }} is hiring for a {{ $json['Job Title'] }}.\"\n\nThe tone must be professional, friendly, and easy to understand.\n\nCrucially, avoid high-level marketing jargon or complex AI-related terminology. Keep the language simple and direct.\n\nFocus the message on the two main benefits: filling the role faster and more affordably. Mention the 30-40% savings.\n\nThe total word count for the body must be under 120 words.\n\nEnd with a soft, low-pressure call-to-action, such as asking if they are open to exploring alternative ways to build their team",
"batching": {},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.7
},
{
"id": "2c3b430d-d1bb-42d6-ab31-88ced73e58f3",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-912,
-32
],
"parameters": {
"height": 360,
"content": "## \u25b6\ufe0f Start Workflow\n\n\n**Manually triggers the entire lead generation process.**"
},
"typeVersion": 1
},
{
"id": "0d3f4c5f-c716-40ab-87b3-e5f74f705e65",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-512,
-176
],
"parameters": {
"width": 260,
"height": 440,
"content": "## Run the LinkedIn Job Scraper from Apify\n\n\nScrape LinkedIn Job Postings:\n\nUses Apify to find companies that are actively hiring based on a specific job search URL."
},
"typeVersion": 1
},
{
"id": "3743dc33-a59f-4ee4-95a2-9956c99c3981",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
16,
-112
],
"parameters": {
"width": 260,
"height": 420,
"content": "## Get dataset Items\n\nCollect Scraped Data:\n\nRetrieves the list of job postings and company details scraped by Apify."
},
"typeVersion": 1
},
{
"id": "8bb80fc2-cd66-4664-8b44-16fb8776a61c",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
512,
-48
],
"parameters": {
"width": 260,
"height": 420,
"content": "## Checks Company Size < 250\n\nFilter by Company Size:\n\nOnly allows companies with fewer than 250 employees to pass through."
},
"typeVersion": 1
},
{
"id": "2425cb33-44ce-411b-a01d-aede93c801b5",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1072,
496
],
"parameters": {
"color": 5,
"height": 100,
"content": "## Rmeove Duplicate Entries\n"
},
"typeVersion": 1
},
{
"id": "e5937705-ff40-41c7-bb0a-3864fac0e9dc",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-448,
368
],
"parameters": {
"color": 5,
"height": 120,
"content": "## Rmeove HR Related Companies"
},
"typeVersion": 1
},
{
"id": "17a39567-8afb-4faa-a29f-ca7522cf3408",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
96,
368
],
"parameters": {
"color": 5,
"height": 120,
"content": "## Prepare Final Company Details"
},
"typeVersion": 1
},
{
"id": "603bc9a8-e1be-49e2-a789-2bc84da68ee2",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-816,
736
],
"parameters": {
"color": 5,
"height": 80,
"content": "## Check domain Existence"
},
"typeVersion": 1
},
{
"id": "ee151293-9743-4df6-bf8c-fab51cf5df10",
"name": "Limit Companies Search",
"type": "n8n-nodes-base.limit",
"position": [
-128,
848
],
"parameters": {
"maxItems": 5
},
"typeVersion": 1
},
{
"id": "6f6e8313-f32e-4bd1-8ff8-973593afd95d",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
-176,
752
],
"parameters": {
"color": 5,
"height": 80,
"content": "## Limit Company Search"
},
"typeVersion": 1
},
{
"id": "00d91745-b097-4049-805e-8133294b46fe",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1488,
1248
],
"parameters": {
"color": 6,
"height": 260,
"content": "## Apollo Get Targeted Personnel\n\n\nFind Decision-Makers:\n\nSearches Apollo.io using the company domain to find key contacts (VPs, Directors, etc.)."
},
"typeVersion": 1
},
{
"id": "f7572335-877a-4033-82f8-bb7bda1a38ff",
"name": "Sticky Note10",
"type": "n8n-nodes-base.stickyNote",
"position": [
-848,
1088
],
"parameters": {
"color": 6,
"height": 260,
"content": "## Sanitising Person Details\n\nClean Person Data:\n\nStructures the contact details and removes duplicates to create a clean list of people."
},
"typeVersion": 1
},
{
"id": "786da361-b3f8-45ee-a4d5-4b1a0a00c9c7",
"name": "Sanitising Person Details",
"type": "n8n-nodes-base.code",
"position": [
-768,
1360
],
"parameters": {
"jsCode": "// Flatten + dedupe by (person.id + companyName)\nlet results = [];\nlet seen = new Set();\n\nitems.forEach(item => {\n const people = item.json.people || [];\n\n people.forEach(person => {\n if (!person.id) return;\n\n const company = person.organization || {};\n const uniqueKey = person.id + \"|\" + (company.name || \"\"); \n\n if (seen.has(uniqueKey)) return;\n seen.add(uniqueKey);\n\n let websiteUrl = company.website_url || null;\n let domain = company.primary_domain || null;\n\n if (!domain && websiteUrl) {\n try {\n const parsedUrl = new URL(websiteUrl);\n domain = parsedUrl.hostname.replace(/^www\\./, \"\");\n } catch (err) {\n domain = websiteUrl.replace(/^(https?:\\/\\/)?(www\\.)?/, \"\").split(/[/?#]/)[0];\n }\n }\n\n results.push({\n json: {\n person: { // \ud83d\udc48 wrapped object\n uniqueKey: uniqueKey,\n personId: person.id || null,\n firstName: person.first_name || null,\n lastName: person.last_name || null,\n personLinkedInUrl: person.linkedin_url || null,\n title: person.title || null,\n city: person.city || null,\n country: person.country || null,\n companyName: company.name || null,\n companyWebsite: websiteUrl,\n primaryDomain: domain,\n companyLinkedInUrl: company.linkedin_url || null\n }\n }\n });\n });\n});\n\nreturn results;\n"
},
"typeVersion": 2
},
{
"id": "f847fb0f-f82b-47c9-a493-9e859bc16a4e",
"name": "Sticky Note11",
"type": "n8n-nodes-base.stickyNote",
"position": [
-576,
1840
],
"parameters": {
"color": 6,
"height": 260,
"content": "## Apollo Email Finder\n\nFind Verified Emails:\n\nFor each contact, this node asks Apollo.io to find their professional email address."
},
"typeVersion": 1
},
{
"id": "18a68ac3-c63f-44aa-9169-a080eb1a21ce",
"name": "Sticky Note12",
"type": "n8n-nodes-base.stickyNote",
"position": [
-48,
1840
],
"parameters": {
"color": 6,
"height": 220,
"content": "## Sanitising Email Details\n\nIsolate Email Data:\n\nPrepares the found email addresses for merging"
},
"typeVersion": 1
},
{
"id": "2713732b-136d-4f9d-8964-ef5b54adeff6",
"name": "Sticky Note13",
"type": "n8n-nodes-base.stickyNote",
"position": [
400,
1296
],
"parameters": {
"color": 4,
"width": 280,
"height": 240,
"content": "## Merge Data\n\nCombine Data Streams:\n\nMerges the company data, the person data, and the email data together."
},
"typeVersion": 1
},
{
"id": "20fc29b2-1b85-4f55-847f-51161415391b",
"name": "Sticky Note14",
"type": "n8n-nodes-base.stickyNote",
"position": [
768,
1056
],
"parameters": {
"color": 4,
"width": 280,
"height": 240,
"content": "## Structuring Complete Details of Person\n\nCreate Final Lead Profile:\n\nCombines all three data streams into a single, complete lead record for each person."
},
"typeVersion": 1
},
{
"id": "6a07323e-c5aa-4cfa-8f8b-19662806e35b",
"name": "Sticky Note15",
"type": "n8n-nodes-base.stickyNote",
"position": [
928,
352
],
"parameters": {
"color": 3,
"width": 280,
"height": 240,
"content": "## Save Leads to Google Sheets\n\nAppends each complete lead profile as a new row in the master spreadsheet."
},
"typeVersion": 1
},
{
"id": "0b81960f-6d52-498d-9bd7-34689431fb88",
"name": "Sticky Note16",
"type": "n8n-nodes-base.stickyNote",
"position": [
1408,
336
],
"parameters": {
"color": 3,
"width": 280,
"height": 260,
"content": "## Fetching Leads Data\n\nRead Leads for AI:\n\nReads the newly saved leads from the sheet to begin the email generation phase."
},
"typeVersion": 1
},
{
"id": "d19a3c2d-ec40-4263-aa09-799f3ab25e7a",
"name": "Sticky Note17",
"type": "n8n-nodes-base.stickyNote",
"position": [
2080,
352
],
"parameters": {
"color": 3,
"width": 280,
"height": 300,
"content": "## Validates Email Id and Email Content\n\nCheck Before AI Processing:\n\nFilters for leads that have a valid email but do NOT yet have a generated subject or body."
},
"typeVersion": 1
},
{
"id": "0ccfe835-fc19-4ffa-acf8-644bc6149633",
"name": "Sticky Note18",
"type": "n8n-nodes-base.stickyNote",
"position": [
1408,
1152
],
"parameters": {
"color": 2,
"width": 280,
"height": 180,
"content": "## Apply Final Filter\n\nApplies a final condition before sending data to the AI model (e.g., for batching or testing).\n\n"
},
"typeVersion": 1
},
{
"id": "fd60f2ef-f30c-4450-9ce4-273946d0f3ed",
"name": "Sticky Note19",
"type": "n8n-nodes-base.stickyNote",
"position": [
1952,
816
],
"parameters": {
"color": 2,
"width": 360,
"height": 240,
"content": "## Lead Email Generator\n\nAI Prompt Engine:\n\nTakes the lead data, combines it with the prompt, and sends it to the Gemini model.\n\n"
},
"typeVersion": 1
},
{
"id": "14f000f8-c23b-43fb-9dc8-53c056d09345",
"name": "Sticky Note20",
"type": "n8n-nodes-base.stickyNote",
"position": [
1792,
1520
],
"parameters": {
"color": 2,
"width": 360,
"height": 240,
"content": "## Google Gemini Chat Model\n\nGoogle Gemini Model:\n\nThe AI model that actually writes the email based on the provided data and instructions.\n\n"
},
"typeVersion": 1
},
{
"id": "17ef075d-dde3-4999-9868-f78f867fa322",
"name": "Sticky Note21",
"type": "n8n-nodes-base.stickyNote",
"position": [
2448,
816
],
"parameters": {
"color": 2,
"width": 360,
"height": 240,
"content": "## Update Sheet with Email\n\nUpdate Sheet with AI Email:\n\nSaves the generated subject and email body back into the correct row for the lead in Google Sheets.\n\n"
},
"typeVersion": 1
},
{
"id": "d7ec9db4-05eb-4e9c-8916-26b046252611",
"name": "Sticky Note22",
"type": "n8n-nodes-base.stickyNote",
"position": [
2416,
1536
],
"parameters": {
"color": 2,
"width": 360,
"height": 240,
"content": "## Structured Output Parser\n\nFormat AI Output:\n\nTakes the raw text from Gemini and structures it into clean JSON (subject and email_body).\n\n"
},
"typeVersion": 1
},
{
"id": "26ab04ae-8f36-4268-ac75-0628e12e321d",
"name": "Sticky Note23",
"type": "n8n-nodes-base.stickyNote",
"position": [
2880,
1200
],
"parameters": {
"color": 2,
"width": 440,
"height": 240,
"content": "## Need Help? \n\nWe develop tailored workflow to save youe valuable time. Should you have any questions or wish to explore more custom automation solutions, we would be happy to connect\n\n\n### Email: getstarted@intuz.com\n### Website: https://www.intuz.com/\n\n"
},
"typeVersion": 1
},
{
"id": "30bffaa6-f024-4725-a969-06f489de54d1",
"name": "Merge Data",
"type": "n8n-nodes-base.merge",
"position": [
480,
1120
],
"parameters": {
"numberInputs": 3
},
"typeVersion": 3.2
},
{
"id": "db0db762-142e-4ea8-8ff3-f868fd7d262c",
"name": "Filter for Batching",
"type": "n8n-nodes-base.filter",
"position": [
1520,
1008
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "fed38656-1a21-4b77-babe-3c49a6f36124",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $json.row_number }}",
"rightValue": 83
}
]
}
},
"typeVersion": 2.2
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "75ee3ba0-b483-48b3-a185-cd0aaec04290",
"connections": {
"Merge Data": {
"main": [
[
{
"node": "Structuring Complete Details of Person",
"type": "main",
"index": 0
}
]
]
},
"Get dataset Items": {
"main": [
[
{
"node": "Checks Company Size < 250",
"type": "main",
"index": 0
}
]
]
},
"Remove Duplicates": {
"main": [
[
{
"node": "Removes HR Related Industry",
"type": "main",
"index": 0
}
]
]
},
"Apollo Email Finder": {
"main": [
[
{
"node": "Sanitising Email Details",
"type": "main",
"index": 0
}
]
]
},
"Fetching Leads Data": {
"main": [
[
{
"node": "Validates Email Id and Email Content",
"type": "main",
"index": 0
}
]
]
},
"Filter for Batching": {
"main": [
[
{
"node": "Lead Email Generator",
"type": "main",
"index": 0
}
]
]
},
"Lead Email Generator": {
"main": [
[
{
"node": "Update Sheet with Email",
"type": "main",
"index": 0
}
]
]
},
"Adding Leads to Sheets": {
"main": [
[
{
"node": "Fetching Leads Data",
"type": "main",
"index": 0
}
]
]
},
"Limit Companies Search": {
"main": [
[
{
"node": "Merge Data",
"type": "main",
"index": 0
},
{
"node": "Apollo Get Targeted Personnel",
"type": "main",
"index": 0
}
]
]
},
"Checks Domain Existence": {
"main": [
[
{
"node": "Limit Companies Search",
"type": "main",
"index": 0
}
]
]
},
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "Lead Email Generator",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Sanitising Email Details": {
"main": [
[
{
"node": "Merge Data",
"type": "main",
"index": 2
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Lead Email Generator",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Checks Company Size < 250": {
"main": [
[
{
"node": "Remove Duplicates",
"type": "main",
"index": 0
}
]
]
},
"Sanitising Person Details": {
"main": [
[
{
"node": "Apollo Email Finder",
"type": "main",
"index": 0
},
{
"node": "Merge Data",
"type": "main",
"index": 1
}
]
]
},
"Removes HR Related Industry": {
"main": [
[
{
"node": "Prepare Final Company Details",
"type": "main",
"index": 0
}
]
]
},
"Run the LinkedIn Job Scraper": {
"main": [
[
{
"node": "Get dataset Items",
"type": "main",
"index": 0
}
]
]
},
"Apollo Get Targeted Personnel": {
"main": [
[
{
"node": "Sanitising Person Details",
"type": "main",
"index": 0
}
]
]
},
"Prepare Final Company Details": {
"main": [
[
{
"node": "Checks Domain Existence",
"type": "main",
"index": 0
}
]
]
},
"Validates Email Id and Email Content": {
"main": [
[
{
"node": "Filter for Batching",
"type": "main",
"index": 0
}
]
]
},
"When clicking \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "Run the LinkedIn Job Scraper",
"type": "main",
"index": 0
}
]
]
},
"Structuring Complete Details of Person": {
"main": [
[
{
"node": "Adding Leads to Sheets",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Community nodes are used in this workflow. B2B Sales Teams & SDRs Recruitment Agencies & Tech Recruiters Startup Founders Growth Marketing Teams Scrape Hiring Signals: The workflow starts by using an Apify scraper to find companies actively hiring for specific roles on LinkedIn…
Source: https://n8n.io/workflows/9219/ — 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.
[VICTOR] Google Maps Extractor. Uses formTrigger, outputParserStructured, lmChatOpenAi, httpRequest. Event-driven trigger; 21 nodes.
video-generator. Uses @apify/n8n-nodes-apify, chainLlm, lmChatMistralCloud, outputParserStructured. Event-driven trigger; 15 nodes.
Visual Regression Testing With Apify And Ai Vision Model. Uses googleDrive, lmChatGoogleGemini, outputParserStructured, stickyNote. Scheduled trigger; 34 nodes.
This n8n workflow is a proof-of-concept template exploring how we might work with multimodal LLMs and their multi-image analysis capabilities. In this demo, we compare 2 screenshots of a webpage taken
The Recap AI - Nano Banana Static Ad Spinner. Uses formTrigger, @mendable/n8n-nodes-firecrawl, chainLlm, lmChatGoogleGemini. Event-driven trigger; 31 nodes.