This workflow corresponds to n8n.io template #9433 — we link there as the canonical source.
This workflow follows the Agent → Gmail 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": "RGhbI0ICGWVFNcVv",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Enrich and score leads with AI",
"tags": [],
"nodes": [
{
"id": "b66eb945-3521-4613-948d-a75c36ad09c4",
"name": "Validate & Parse Input",
"type": "n8n-nodes-base.code",
"position": [
-784,
480
],
"parameters": {
"jsCode": "const chatInput = $json.chatInput ? $json.chatInput.trim() : '';\n\nif (!chatInput) {\n return [{json: {error: 'No input provided', validationPassed: false}}];\n}\n\nconst parts = chatInput.split(',').map(p => p.trim());\nlet email, name;\n\nif (parts.length === 2) {\n email = parts[0].toLowerCase().replace(/['\"]/g, '');\n name = parts[1].replace(/['\"]/g, '');\n} else if (parts.length === 1) {\n email = parts[0].toLowerCase().replace(/['\"]/g, '');\n name = null;\n} else {\n return [{json: {error: 'Invalid format. Use: email or email, name', validationPassed: false}}];\n}\n\nconst emailRegex = new RegExp('^[^\\\\s@]+@[^\\\\s@]+\\\\.[^\\\\s@]+$');\nif (!emailRegex.test(email)) {\n return [{json: {error: 'Invalid email format: ' + email, validationPassed: false}}];\n}\n\nconst domain = email.split('@')[1];\nconst isFreeEmail = ['gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com'].includes(domain);\n\nreturn [{\n json: {\n email: email,\n name: name,\n domain: domain,\n isFreeEmail: isFreeEmail,\n originalInput: chatInput,\n timestamp: new Date().toISOString(),\n validationPassed: true\n }\n}];"
},
"typeVersion": 2
},
{
"id": "13770db8-7d8e-477f-ba58-6996ad31fc9a",
"name": "PDL Enrich",
"type": "n8n-nodes-base.httpRequest",
"position": [
-608,
384
],
"parameters": {
"url": "https://api.peopledatalabs.com/v5/person/enrich",
"options": {},
"sendQuery": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"queryParameters": {
"parameters": [
{
"name": "email",
"value": "={{ $json.email }}"
},
{
"name": "pretty",
"value": "true"
}
]
}
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2,
"continueOnFail": true
},
{
"id": "0d603f14-9665-4563-aa6c-3f48f1b9d57e",
"name": "Individual Research",
"type": "n8n-nodes-base.perplexity",
"position": [
-368,
272
],
"parameters": {
"options": {},
"messages": {
"message": [
{
"content": "=Research {{ $json.data.full_name }} at {{ $json.data.job_company_name }} for B2B sales context.\n\nFocus on:\n1. Recent career moves or promotions (last 6 months)\n2. Professional achievements and thought leadership\n3. Speaking engagements or publications\n4. Relevant timing signals for outreach\n\nProvide ONLY actionable insights for sales in under 150 words.\n\nFormat:\nRECENT ACTIVITY: [Key recent developments]\nEXPERTISE: [Professional focus areas]\nOUTREACH ANGLE: [Best conversation starter]\nTIMING: [High/Medium/Low urgency]"
}
]
},
"requestOptions": {}
},
"credentials": {
"perplexityApi": {
"name": "<your credential>"
}
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "e40a3d01-cf95-4a7e-818c-3df1609c2b61",
"name": "Company Research",
"type": "n8n-nodes-base.perplexity",
"position": [
-368,
416
],
"parameters": {
"options": {},
"messages": {
"message": [
{
"content": "=Research {{ $json.data.job_company_name }} for B2B sales intelligence.\n\nFocus ONLY on last 90 days:\n1. Funding rounds, acquisitions, or financial news\n2. Executive changes or restructuring\n3. New product launches or market expansion\n4. Technology stack changes or digital transformation\n5. Growth signals (hiring, new offices, partnerships)\n\nProvide under 150 words.\n\nFormat:\nRECENT DEVELOPMENTS: [Key changes]\nBUYING SIGNALS: [What suggests they're in market]\nCOMPANY HEALTH: [Financial/growth status]\nPRIORITY: [High/Medium/Low for sales timing]"
}
]
},
"requestOptions": {}
},
"credentials": {
"perplexityApi": {
"name": "<your credential>"
}
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "13eb8525-4863-4b36-8291-1dc811314255",
"name": "Merge Enrichment Data",
"type": "n8n-nodes-base.code",
"position": [
224,
416
],
"parameters": {
"jsCode": "const inputs = $input.all();\n\nconst enrichedData = {\n contact: {\n email: null,\n name: null\n },\n enrichment: {\n pdl: {},\n individual: {},\n company: {},\n linkedin: {}\n },\n metadata: {\n enrichmentTimestamp: new Date().toISOString(),\n sourcesSuccessful: [],\n sourcesFailed: []\n }\n};\n\ninputs.forEach((input, index) => {\n const data = input.json;\n \n if (index === 0 && data.choices && data.choices[0] && data.choices[0].message && data.choices[0].message.content) {\n const content = data.choices[0].message.content;\n enrichedData.enrichment.individual = {\n rawResearch: content,\n recentActivity: extractSection(content, 'RECENT ACTIVITY'),\n expertise: extractSection(content, 'EXPERTISE'),\n outreachAngle: extractSection(content, 'OUTREACH ANGLE'),\n timing: extractSection(content, 'TIMING')\n };\n enrichedData.metadata.sourcesSuccessful.push('Individual Research');\n }\n \n else if (index === 1 && data && !data.error) {\n const pdl = data.data || data;\n enrichedData.enrichment.pdl = {\n fullName: pdl.full_name,\n jobTitle: pdl.job_title,\n companyName: pdl.job_company_name,\n companySize: pdl.job_company_size,\n industry: pdl.job_company_industry,\n seniorityLevel: pdl.job_title_levels,\n linkedinUrl: pdl.linkedin_url,\n location: pdl.location_name,\n skills: pdl.skills\n };\n enrichedData.contact.name = pdl.full_name;\n enrichedData.metadata.sourcesSuccessful.push('PDL');\n }\n \n else if (index === 2 && data.choices && data.choices[0] && data.choices[0].message && data.choices[0].message.content) {\n const content = data.choices[0].message.content;\n enrichedData.enrichment.company = {\n rawResearch: content,\n developments: extractSection(content, 'RECENT DEVELOPMENTS'),\n buyingSignals: extractSection(content, 'BUYING SIGNALS'),\n companyHealth: extractSection(content, 'COMPANY HEALTH'),\n priority: extractSection(content, 'PRIORITY')\n };\n enrichedData.metadata.sourcesSuccessful.push('Company Research');\n }\n \n else if (index === 3 && data && Array.isArray(data) && data.length > 0) {\n const profile = data[0];\n enrichedData.enrichment.linkedin = {\n headline: profile.headline,\n summary: profile.summary,\n recentPosts: profile.posts ? profile.posts.slice(0, 5) : [],\n connectionsCount: profile.connectionsCount,\n postsAnalyzed: true\n };\n enrichedData.metadata.sourcesSuccessful.push('LinkedIn');\n }\n \n else if (index === 4 && data.validationPassed) {\n enrichedData.contact.email = data.email;\n enrichedData.contact.domain = data.domain;\n enrichedData.contact.isFreeEmail = data.isFreeEmail;\n }\n});\n\nconst qualityScore = calculateQuality(enrichedData);\nenrichedData.metadata.dataQualityScore = qualityScore;\n\nfunction extractSection(text, header) {\n const pattern = header + ': ';\n const startIdx = text.indexOf(pattern);\n if (startIdx === -1) return 'N/A';\n const afterHeader = text.substring(startIdx + pattern.length);\n const endIdx = afterHeader.search(/\\n[A-Z]/);\n return endIdx === -1 ? afterHeader.trim() : afterHeader.substring(0, endIdx).trim();\n}\n\nfunction calculateQuality(data) {\n let score = 0;\n if (data.enrichment.pdl.fullName) score += 25;\n if (data.enrichment.individual.recentActivity !== 'N/A') score += 25;\n if (data.enrichment.company.developments !== 'N/A') score += 25;\n if (data.enrichment.linkedin.postsAnalyzed) score += 25;\n return score;\n}\n\nreturn [{ json: enrichedData }];"
},
"typeVersion": 2
},
{
"id": "c23aed66-e846-4781-a030-6cfb42b397ef",
"name": "Merge All Sources",
"type": "n8n-nodes-base.merge",
"position": [
32,
368
],
"parameters": {
"numberInputs": 5
},
"typeVersion": 3.2
},
{
"id": "51e743be-5ec5-4de3-9dfb-0e4ef85f511a",
"name": "Parse & Structure Output",
"type": "n8n-nodes-base.code",
"position": [
704,
416
],
"parameters": {
"jsCode": "const raw = $input.first().json.output;\n\nlet scoring;\ntry {\n let cleaned = raw.replace(/```json\\n?|```\\n?/g, '').trim();\n cleaned = cleaned.replace(/,(\\s*[}\\]])/g, '$1');\n scoring = JSON.parse(cleaned);\n \n} catch (err) {\n const extract = (field) => {\n const regex = new RegExp('\"' + field + '\":\\\\s*\"([^\"]*(?:\\\\\\\\.[^\"]*)*)\"', 's');\n const match = raw.match(regex);\n return match ? match[1].replace(/\\\\n/g, '\\n').replace(/\\\\\"/g, '\"') : null;\n };\n \n const extractArray = (field) => {\n const regex = new RegExp('\"' + field + '\":\\\\s*\\\\[([^\\\\]]+)\\\\]', 's');\n const match = raw.match(regex);\n if (!match) return [];\n return match[1].split(',').map(s => s.trim().replace(/^\"|\"$/g, ''));\n };\n \n const extractNumber = (field) => {\n const regex = new RegExp('\"' + field + '\":\\\\s*(\\\\d+)');\n const match = raw.match(regex);\n return match ? parseInt(match[1]) : 0;\n };\n \n const extractObject = (field) => {\n const regex = new RegExp('\"' + field + '\":\\\\s*({[^}]+})');\n const match = raw.match(regex);\n if (!match) return {};\n try {\n return JSON.parse(match[1]);\n } catch {\n return {};\n }\n };\n \n scoring = {\n email: extract('email'),\n name: extract('name'),\n title: extract('title'),\n companyName: extract('companyName'),\n companySize: extract('companySize'),\n industry: extract('industry'),\n seniorityLevel: extractArray('seniorityLevel'),\n linkedinUrl: extract('linkedinUrl'),\n individualResearch: extract('individualResearch'),\n companyResearch: extract('companyResearch'),\n dataQualityScore: extractNumber('dataQualityScore'),\n leadScore: extractNumber('leadScore'),\n scoreBreakdown: extractObject('scoreBreakdown'),\n icpMatch: extractObject('icpMatch'),\n keyInsights: extractArray('keyInsights'),\n outreachRecommendation: extract('outreachRecommendation'),\n conversationStarters: extractArray('conversationStarters'),\n timingOpportunities: extractArray('timingOpportunities'),\n redFlags: extractArray('redFlags'),\n nextAction: extract('nextAction'),\n confidenceLevel: extract('confidenceLevel'),\n routingCategory: extract('routingCategory')\n };\n}\n\nconst finalLead = {\n email: scoring.email,\n name: scoring.name,\n title: scoring.title,\n companyName: scoring.companyName,\n companySize: scoring.companySize,\n industry: scoring.industry,\n seniorityLevel: scoring.seniorityLevel,\n linkedinUrl: scoring.linkedinUrl,\n individualResearch: scoring.individualResearch,\n companyResearch: scoring.companyResearch,\n dataQualityScore: scoring.dataQualityScore,\n leadScore: scoring.leadScore,\n scoreBreakdown: scoring.scoreBreakdown,\n scoreReasoning: scoring.leadScore + '/10 - ' + Object.entries(scoring.scoreBreakdown || {}).map(function(pair) { return pair[0] + ': ' + pair[1]; }).join(', '),\n icpMatch: scoring.icpMatch,\n companySizeMatch: scoring.icpMatch ? scoring.icpMatch.companySizeMatch : null,\n industryMatch: scoring.icpMatch ? scoring.icpMatch.industryMatch : null,\n titleMatch: scoring.icpMatch ? scoring.icpMatch.titleMatch : null,\n keyInsights: scoring.keyInsights || [],\n outreachRecommendation: scoring.outreachRecommendation,\n conversationStarters: scoring.conversationStarters || [],\n timingOpportunities: scoring.timingOpportunities || [],\n redFlags: scoring.redFlags || [],\n nextAction: scoring.nextAction,\n confidenceLevel: scoring.confidenceLevel,\n routingCategory: scoring.routingCategory,\n processedAt: new Date().toISOString()\n};\n\nreturn [{ json: finalLead }];"
},
"typeVersion": 2
},
{
"id": "7589e25e-910e-4304-8449-27ace6765c1c",
"name": "Route by Score",
"type": "n8n-nodes-base.switch",
"position": [
896,
400
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Hot Lead",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "99013e96-7d32-48fc-907d-d524c3cfb81d",
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.leadScore }}",
"rightValue": 8
}
]
},
"renameOutput": true
},
{
"outputKey": "Warm Lead",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "2b850a5b-5f06-482b-925c-0dee244e61ed",
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.leadScore }}",
"rightValue": 5
},
{
"id": "186f945d-b433-44e4-8954-e89781754d4e",
"operator": {
"type": "number",
"operation": "lt"
},
"leftValue": "={{ $json.leadScore }}",
"rightValue": 8
}
]
},
"renameOutput": true
},
{
"outputKey": "Cold Lead",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d54da592-8730-409e-80e1-d4550c85ae9d",
"operator": {
"type": "number",
"operation": "lt"
},
"leftValue": "={{ $json.leadScore }}",
"rightValue": 5
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "7ed0a825-6e4c-49ef-92b7-3f1ec790beb0",
"name": "Send Hot Lead Slack Alert",
"type": "n8n-nodes-base.slack",
"position": [
2048,
144
],
"parameters": {
"text": "={{ $json.content.parts[0].text }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C096FHNCPUM",
"cachedResultName": "all-connors-personal-slack"
},
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "261f7748-68b5-4839-9df4-128af5724b6c",
"name": "Parse Email JSON",
"type": "n8n-nodes-base.code",
"position": [
1872,
320
],
"parameters": {
"jsCode": "const inputData = $input.first().json;\n\nconst raw = inputData.content && inputData.content.parts && inputData.content.parts[0] ? inputData.content.parts[0].text : null;\n\nif (!raw) {\n return [{json: {error: 'Could not find email content in response'}}];\n}\n\nconst cleanedRaw = raw.replace(/```json\\n?|```\\n?/g, '').trim();\nconst emailData = JSON.parse(cleanedRaw);\n\nreturn [{\n json: {\n to: emailData.email,\n subject: emailData.subject,\n body: emailData.body\n }\n}];"
},
"typeVersion": 2
},
{
"id": "7435b309-71ef-447f-b90d-0024e576a6a2",
"name": "Send Hot Lead Email",
"type": "n8n-nodes-base.gmail",
"position": [
2048,
320
],
"parameters": {
"sendTo": "={{ $json.to }}",
"message": "={{ $json.body }}",
"options": {
"appendAttribution": false
},
"subject": "={{ $json.subject }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "bf14b094-a26d-4eac-882c-f4255b4907e8",
"name": "Send Warm Lead to Digest",
"type": "n8n-nodes-base.slack",
"position": [
2048,
496
],
"parameters": {
"text": "={{ $json.content.parts[0].text }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C096FHNCPUM",
"cachedResultName": "all-connors-personal-slack"
},
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "305c329d-2e65-42e0-b165-e94001ae3b1b",
"name": "Format for CRM",
"type": "n8n-nodes-base.code",
"position": [
1552,
672
],
"parameters": {
"jsCode": "const lead = $json;\n\nreturn [{\n json: {\n email: lead.email,\n firstname: lead.name ? lead.name.split(' ')[0] : null,\n lastname: lead.name ? lead.name.split(' ').slice(1).join(' ') : null,\n jobtitle: lead.title,\n company: lead.companyName,\n linkedin_url: lead.linkedinUrl,\n lead_score: lead.leadScore,\n lead_score_reasoning: lead.scoreReasoning,\n routing_category: lead.routingCategory,\n icp_company_size_match: lead.companySizeMatch,\n icp_industry_match: lead.industryMatch,\n icp_title_match: lead.titleMatch,\n key_insights: lead.keyInsights ? lead.keyInsights.join(' | ') : null,\n conversation_starters: lead.conversationStarters ? lead.conversationStarters.join(' | ') : null,\n timing_opportunities: lead.timingOpportunities ? lead.timingOpportunities.join(' | ') : null,\n outreach_recommendation: lead.outreachRecommendation,\n red_flags: lead.redFlags ? lead.redFlags.join(' | ') : null,\n individual_research_summary: lead.individualResearch,\n company_research_summary: lead.companyResearch,\n data_quality_score: lead.dataQualityScore,\n enrichment_sources: lead.sourcesUsed ? lead.sourcesUsed.join(', ') : null,\n last_enrichment_date: lead.processedAt,\n lifecyclestage: lead.routingCategory === 'hot' ? 'salesqualifiedlead' : 'lead',\n hs_lead_status: lead.routingCategory === 'hot' ? 'OPEN' : 'NEW'\n }\n}];"
},
"typeVersion": 2
},
{
"id": "aca601b2-b493-4682-919a-88e0bd4f404f",
"name": "Upsert to HubSpot CRM",
"type": "n8n-nodes-base.hubspot",
"notes": "Enable after configuring HubSpot credentials",
"position": [
2048,
672
],
"parameters": {
"email": "={{ $json.email }}",
"options": {},
"additionalFields": {
"customPropertiesUi": {
"customPropertiesValues": [
{
"value": "={{ $json.firstname }}",
"property": "firstname"
},
{
"value": "={{ $json.lastname }}",
"property": "lastname"
},
{
"value": "={{ $json.jobtitle }}",
"property": "jobtitle"
},
{
"value": "={{ $json.company }}",
"property": "company"
},
{
"value": "={{ $json.lead_score }}",
"property": "lead_score"
},
{
"value": "={{ $json.lifecyclestage }}",
"property": "lifecyclestage"
}
]
}
}
},
"typeVersion": 2
},
{
"id": "c87419fe-28ab-45cf-89c3-b9f9d9de3efd",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
384,
416
],
"parameters": {
"text": "=You are a B2B lead scoring AI with access to ICP rules stored in a Google Doc.\n\nCRITICAL FIRST STEP: Use the available Google Docs tool to fetch the ICP scoring rules document before analyzing the lead.\n\nLead Data:\n{{ JSON.stringify($json, null, 2) }}\n\nSCORING PROCESS:\n1. Fetch ICP rules from the doc\n2. Score each component (0-3 for company, 0-3 for title, 0-2 for signals, 0-2 for timing) based on the rules\n3. CRITICAL: Calculate leadScore by ADDING the four breakdown scores together\n leadScore equals companyFit plus titleFit plus buyingSignals plus timing\n4. Determine routing category based on total score:\n - 8-10 equals hot\n - 5-7 equals warm \n - 0-4 equals cold\n\nSCORING RULES:\n- Company Fit (0-3): Compare company size, industry, and geography against ICP criteria in doc\n- Title Fit (0-3): Match persona title against ICP persona tiers in doc\n- Buying Signals (0-2): Count strong/medium signals from research data\n- Timing (0-2): Assess urgency based on recent changes and signals\n\nReturn ONLY valid JSON (no markdown, no code blocks) with these fields: email, name, title, companyName, companySize, industry, seniorityLevel, linkedinUrl, individualResearch, companyResearch, dataQualityScore, leadScore (sum of breakdown scores), scoreBreakdown object with companyFit/titleFit/buyingSignals/timing, icpMatch object with companySizeMatch/industryMatch/titleMatch booleans, keyInsights array, outreachRecommendation string, conversationStarters array, timingOpportunities array, redFlags array, nextAction string, confidenceLevel string, routingCategory string based on score thresholds above.",
"options": {},
"promptType": "define"
},
"typeVersion": 2.2
},
{
"id": "cbf742e7-a18e-47e8-85e2-6537abe0b4f9",
"name": "Anthropic Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
384,
608
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "claude-sonnet-4-20250514",
"cachedResultName": "Claude 4 Sonnet"
},
"options": {}
},
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "9c9f0f0f-b6a3-4f72-88e5-760ab64305d3",
"name": "Format Hot Lead Slack",
"type": "@n8n/n8n-nodes-langchain.googleGemini",
"position": [
1552,
144
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "models/gemini-2.5-flash",
"cachedResultName": "models/gemini-2.5-flash"
},
"options": {},
"messages": {
"values": [
{
"content": "=Create a concise Slack alert for a HOT LEAD that requires immediate sales attention.\n\nLead Data:\n{{ JSON.stringify($json, null, 2) }}\n\nUsing the data above, create a Slack message in mrkdwn format with this structure:\n\nHOT LEAD ALERT\n\n[name] | [title] at [companyName]\nScore: [leadScore]/10 | [confidenceLevel] confidence\n[email]\n\nKey Insights:\n- [First 3-4 items from keyInsights array as bullets]\n\nWhy This Matters:\n[Pull from timingOpportunities - 1-2 sentences on urgency]\n\nRecommended Approach:\n[outreachRecommendation - keep concise]\n\nConversation Starters:\n- [First 2 from conversationStarters array]\n\nNote: [First redFlag if exists]\n\nNext Action: [nextAction]\n\nKeep it under 300 words and extremely scannable. Use actual values from the JSON data."
}
]
}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "4de89a82-f720-4ee6-88f5-fa35006e4f29",
"name": "Format Hot Lead Email",
"type": "@n8n/n8n-nodes-langchain.googleGemini",
"position": [
1552,
320
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "models/gemini-2.5-flash",
"cachedResultName": "models/gemini-2.5-flash"
},
"options": {},
"messages": {
"values": [
{
"content": "=Create a personalized welcome email for a HOT LEAD.\n\nLead Data:\n{{ JSON.stringify($json, null, 2) }}\n\nRequirements:\n- Warm, professional tone\n- Reference 1-2 relevant insights naturally\n- Clear value proposition for their role/company\n- Soft CTA (calendar link or reply)\n- 100-150 words max\n- Feel human-written, not templated\n\nReturn JSON (include the email from the input) with fields: email (extract from input data), subject (engaging subject line), body (email body with paragraph tags, not HTML angle brackets)."
}
]
}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "e6092336-93a4-402e-b38e-2b6d2a8a5792",
"name": "Format Warm Lead Slack",
"type": "@n8n/n8n-nodes-langchain.googleGemini",
"position": [
1552,
496
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "models/gemini-2.5-flash",
"cachedResultName": "models/gemini-2.5-flash"
},
"options": {},
"messages": {
"values": [
{
"content": "=Create a Slack digest entry for a WARM LEAD.\n\nLead Data:\n{{ JSON.stringify($json, null, 2) }}\n\nUsing the data above, create a message:\n\n[name] | [title] at [companyName]\nScore: [leadScore]/10\n\nQuick Context:\n- [2-3 items from keyInsights]\n\nNext Steps: [nextAction]\n\nKeep it under 150 words. Use actual values from the JSON."
}
]
}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "fc94e4bf-f9ca-45f4-85e2-4d545a76b6ad",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-976,
480
],
"parameters": {
"path": "lead-intake",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2.1
},
{
"id": "55e71e16-4550-47ac-b5fb-7c903903dfa8",
"name": "LinkedIn Profile Scraper",
"type": "@apify/n8n-nodes-apify.apify",
"position": [
-368,
560
],
"parameters": {
"memory": {},
"actorId": {
"__rl": true,
"mode": "url",
"value": "https://console.apify.com/actors/LQQIXN9Othf8f7R5n/input"
},
"timeout": {},
"operation": "Run actor",
"customBody": "={ \"username\": \"{{ $json.data.profiles[0].url }}\" }",
"actorSource": "store",
"waitForFinish": 60,
"authentication": "apifyOAuth2Api"
},
"credentials": {
"apifyOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "cca5c728-3ee5-4192-91e3-33ba69630dc9",
"name": "ICP & Use Case",
"type": "n8n-nodes-base.googleDocsTool",
"position": [
528,
608
],
"parameters": {
"operation": "get",
"documentURL": "https://docs.google.com/document/d/YOUR_DOCUMENT_ID/edit"
},
"credentials": {
"googleDocsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "6d3fcf37-6aa7-45c5-ae0f-49666579be13",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
176,
-144
],
"parameters": {
"color": 4,
"width": 704,
"height": 528,
"content": "## Enrich and score leads with AI\n\nThis workflow automates lead qualification by enriching email addresses with firmographic data from People Data Labs, researching individuals and companies using Perplexity AI, scoring leads against your ICP criteria with Claude, and routing them to appropriate channels.\n\n### What it does:\n- Hot leads (8-10 score) get instant Slack alerts with personalized email drafts\n- Warm leads (5-7) go to a digest channel\n- Cold leads (0-4) log to your CRM only\n- Processing takes 30-60 seconds per lead versus 20 minutes manual research\n- Cost per lead: $0.08-0.15\n\n### Setup required:\n1. Configure webhook path (default: lead-intake)\n2. Add credentials for: PDL, Perplexity, Claude, Slack, Gmail, Google Docs\n3. Create ICP rules Google Doc and update URL in ICP & Use Case node\n4. Optional: Add Apify and HubSpot credentials\n\n### How to use:\nSend POST to webhook with: {\"email\": \"lead@company.com\", \"name\": \"Optional Name\"}"
},
"typeVersion": 1
},
{
"id": "f951f6b2-cae8-4287-bccc-3bcb8090287e",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-656,
256
],
"parameters": {
"width": 176,
"height": 112,
"content": "**Setup Required:**\nCreate Header Auth credential with:\n- Name: X-Api-Key\n- Value: Your PDL API key\n\nAlternative: Use Apollo or Clearbit"
},
"typeVersion": 1
},
{
"id": "d3d0ab31-2b0c-40aa-8ecf-c1c3207482c8",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-432,
704
],
"parameters": {
"content": "**Optional:**\nGet API key from:\nhttps://apify.com/curious_coder/linkedin-profile-scraper\n\nAdd OAuth2 credentials"
},
"typeVersion": 1
},
{
"id": "45baaf4f-6afa-4e21-b04e-b05d091f6e7d",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
496,
768
],
"parameters": {
"width": 150,
"height": 144,
"content": "**Setup Required:**\nReplace documentURL with your ICP rules Google Doc URL\n\nAdd OAuth2 credentials"
},
"typeVersion": 1
},
{
"id": "684eb148-af5f-404c-9307-d8bfe705afa6",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1856,
656
],
"parameters": {
"width": 150,
"height": 196,
"content": "**Optional:**\nEnable node and add credentials for:\n- HubSpot\n- Salesforce\n- Pipedrive\n- Or custom CRM"
},
"typeVersion": 1
},
{
"id": "21a65fe2-b9ad-4b52-ac4d-590edabd0a3f",
"name": "AI Reasoning",
"type": "@n8n/n8n-nodes-langchain.toolThink",
"position": [
656,
608
],
"parameters": {},
"typeVersion": 1.1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "0cc18b9c-0d69-4c44-b726-b00d21fb7afd",
"connections": {
"Webhook": {
"main": [
[
{
"node": "Validate & Parse Input",
"type": "main",
"index": 0
}
]
]
},
"AI Agent": {
"main": [
[
{
"node": "Parse & Structure Output",
"type": "main",
"index": 0
}
]
]
},
"PDL Enrich": {
"main": [
[
{
"node": "Merge All Sources",
"type": "main",
"index": 1
},
{
"node": "Individual Research",
"type": "main",
"index": 0
},
{
"node": "Company Research",
"type": "main",
"index": 0
},
{
"node": "LinkedIn Profile Scraper",
"type": "main",
"index": 0
}
]
]
},
"AI Reasoning": {
"ai_tool": [
[
{
"node": "AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Format for CRM": {
"main": [
[
{
"node": "Upsert to HubSpot CRM",
"type": "main",
"index": 0
}
]
]
},
"ICP & Use Case": {
"ai_tool": [
[
{
"node": "AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Route by Score": {
"main": [
[
{
"node": "Format for CRM",
"type": "main",
"index": 0
},
{
"node": "Format Hot Lead Slack",
"type": "main",
"index": 0
},
{
"node": "Format Hot Lead Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Format for CRM",
"type": "main",
"index": 0
},
{
"node": "Format Warm Lead Slack",
"type": "main",
"index": 0
}
],
[
{
"node": "Format for CRM",
"type": "main",
"index": 0
}
]
]
},
"Company Research": {
"main": [
[
{
"node": "Merge All Sources",
"type": "main",
"index": 2
}
]
]
},
"Parse Email JSON": {
"main": [
[
{
"node": "Send Hot Lead Email",
"type": "main",
"index": 0
}
]
]
},
"Merge All Sources": {
"main": [
[
{
"node": "Merge Enrichment Data",
"type": "main",
"index": 0
}
]
]
},
"Individual Research": {
"main": [
[
{
"node": "Merge All Sources",
"type": "main",
"index": 0
}
]
]
},
"Anthropic Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Format Hot Lead Email": {
"main": [
[
{
"node": "Parse Email JSON",
"type": "main",
"index": 0
}
]
]
},
"Format Hot Lead Slack": {
"main": [
[
{
"node": "Send Hot Lead Slack Alert",
"type": "main",
"index": 0
}
]
]
},
"Merge Enrichment Data": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
},
"Format Warm Lead Slack": {
"main": [
[
{
"node": "Send Warm Lead to Digest",
"type": "main",
"index": 0
}
]
]
},
"Validate & Parse Input": {
"main": [
[
{
"node": "PDL Enrich",
"type": "main",
"index": 0
},
{
"node": "Merge All Sources",
"type": "main",
"index": 4
}
]
]
},
"LinkedIn Profile Scraper": {
"main": [
[
{
"node": "Merge All Sources",
"type": "main",
"index": 3
}
]
]
},
"Parse & Structure Output": {
"main": [
[
{
"node": "Route by Score",
"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.
anthropicApiapifyOAuth2ApigmailOAuth2googleDocsOAuth2ApigooglePalmApihttpHeaderAuthperplexityApislackOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This template uses the Apify LinkedIn Profile Scraper, which is a community node only available in self-hosted n8n installations. The LinkedIn scraping step is optional and can be removed for n8n Cloud compatibility.
Source: https://n8n.io/workflows/9433/ — 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.
Automatically score product usage signals from Amplitude cohorts and route hot leads to sales with enriched context.
This workflow monitors user usage via a webhook and automatically triggers an upsell process when limits are exceeded. It formats incoming data, generates a personalized email using AI, and sends it t
Lead Pipeline v3.0. Uses httpRequest, agent, lmChatAnthropic, toolThink. Webhook trigger; 77 nodes.
Who is this for? Agencies, consultants, and service providers who conduct discovery calls and need to quickly turn conversations into professional proposals.
Flux. Uses lmChatOpenAi, agent, googleGemini, httpRequest. Webhook trigger; 67 nodes.