This workflow corresponds to n8n.io template #14986 — 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 →
{
"nodes": [
{
"id": "33341b07-0972-4005-abb9-cff3c6d1284c",
"name": "Daily Prospect Research",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
496,
944
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "9710e056-4917-4ec9-8f7e-e847c666f9e9",
"name": "Read Upcoming Calls Sheet",
"type": "n8n-nodes-base.googleSheets",
"onError": "continueRegularOutput",
"position": [
752,
944
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "id",
"value": "upcoming_calls"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_SPREADSHEET_ID"
}
},
"typeVersion": 4.7
},
{
"id": "d071b882-237d-460e-b54e-1a4e983b3861",
"name": "Scrape LinkedIn Profile",
"type": "n8n-nodes-base.httpRequest",
"maxTries": 3,
"position": [
1024,
944
],
"parameters": {
"url": "=https://api.brightdata.com/datasets/v3/scrape?dataset_id=gd_l1viktl72bvl7bjuj0&format=json",
"method": "POST",
"options": {
"timeout": 90000
},
"jsonBody": "={{ JSON.stringify({ input: [{ url: $json.url }] }) }}",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"retryOnFail": true,
"typeVersion": 4.2,
"waitBetweenTries": 5000
},
{
"id": "28ded147-d306-4e78-9ed5-191e05fa1a2d",
"name": "Validate BD Response",
"type": "n8n-nodes-base.code",
"position": [
1280,
944
],
"parameters": {
"jsCode": "const input = $input.first().json;\n\n// Handle array response (synchronous success)\nif (Array.isArray(input)) {\n if (input.length === 0) {\n return [{ json: { error: 'Bright Data returned empty results', status: 'no_data' } }];\n }\n return input.map(item => ({ json: { ...item, status: 'ok' } }));\n}\n\n// Handle object response\nif (input.snapshot_id) {\n return [{ json: { error: 'Async response - snapshot not ready', snapshot_id: input.snapshot_id, status: 'async_pending' } }];\n}\n\nif (input.error || input.message) {\n return [{ json: { error: input.error || input.message, status: 'api_error' } }];\n}\n\n// Pass through valid single-object response\nreturn [{ json: { ...input, status: 'ok' } }];"
},
"typeVersion": 2
},
{
"id": "cca84cfe-122d-44d5-b847-239f5c607092",
"name": "Build Call Brief",
"type": "@n8n/n8n-nodes-langchain.agent",
"onError": "continueErrorOutput",
"position": [
2064,
944
],
"parameters": {
"text": "=Build a pre-call intelligence brief for this prospect. Our product: {{ $json.our_product }}. Meeting date: {{ $json.meeting_date }}\n\n{{ JSON.stringify($json) }}",
"options": {
"systemMessage": "You are a sales intelligence analyst. You receive scraped LinkedIn profile data for an upcoming sales call prospect.\n\nYour job is to build a comprehensive pre-call intelligence brief.\n\nAnalyze the profile and produce:\n- career_trajectory: string, summarize their career path and what it tells you about their priorities.\n- recent_activity: string, summarize their recent LinkedIn activity (posts, comments, shares).\n- talking_points: array of exactly 5 strings, specific conversation starters based on their profile.\n Each should reference something concrete from their profile or activity.\n- potential_pain_points: array of strings, likely business challenges based on their role, company, and industry.\n- readiness_score: integer 0-100, how ready this prospect is for a productive sales conversation.\n - 80-100: Strong buying signals, active pain points, clear decision-making authority.\n - 60-80: Good fit, some engagement signals, likely has budget authority.\n - 40-60: Moderate fit, unclear signals, may need nurturing.\n - 0-40: Weak fit, minimal engagement, possibly wrong contact.\n\nAlso include:\n- prospect_name: string\n- current_role: string\n- company: string\n- connection_points: string, any mutual connections, shared interests, or common ground.\n- recommended_approach: string, specific strategy for this call.\n- risk_factors: string, things that could derail the conversation.\n\nCRITICAL OUTPUT RULES:\n- Return ONLY a raw JSON object. Nothing else.\n- No markdown. No code fences. No explanations before or after.\n\nSELF-EVALUATION (mandatory):\nInclude an \"eval\" object in your response with:\n- confidence: float 0.0-1.0, your confidence in the analysis quality\n- reasoning: 1 sentence explaining your confidence level\n- data_quality: \"high\", \"medium\", or \"low\" based on input completeness\n- evidence_count: integer, number of data points you based the analysis on"
},
"promptType": "define"
},
"typeVersion": 3
},
{
"id": "05a921a3-979f-40a2-abd3-cc22ab392c1e",
"name": "GPT-5.5 Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
2064,
1184
],
"parameters": {
"model": "gpt-5.5",
"options": {}
},
"typeVersion": 1
},
{
"id": "51c8d253-573c-4a55-8ce2-ba5a9a6662eb",
"name": "Parse AI Output",
"type": "n8n-nodes-base.code",
"position": [
2320,
944
],
"parameters": {
"jsCode": "const raw = $input.first().json.output || $input.first().json.text || '';\nconst clean = raw.replace(/```json\\n?/g, '').replace(/```\\n?/g, '').trim();\n\nlet parsed;\ntry {\n parsed = JSON.parse(clean);\n} catch (e) {\n parsed = {\n error: 'Failed to parse AI response',\n parse_error: e.message,\n raw_preview: raw.substring(0, 200)\n };\n}\nconst original = $(\"Read Upcoming Calls Sheet\").first().json;\n\nreturn [{ json: { ...original, ...parsed, processed_at: new Date().toISOString() } }];"
},
"typeVersion": 2
},
{
"id": "bf13e930-e188-4bbd-9d42-5964eaf66868",
"name": "IF Confidence >= 0.7",
"type": "n8n-nodes-base.if",
"onError": "continueErrorOutput",
"position": [
2576,
944
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "8807c067-d1cc-484b-9448-da98606ac280",
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.eval.confidence }}",
"rightValue": 0.7
}
]
}
},
"typeVersion": 2.2
},
{
"id": "ca395b2b-a283-4db3-ba45-84f9ac983e4b",
"name": "IF Readiness Score >= 70",
"type": "n8n-nodes-base.if",
"onError": "continueErrorOutput",
"position": [
2832,
816
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "26a6177f-03be-4ce5-8290-24f05a916033",
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.readiness_score }}",
"rightValue": 70
}
]
}
},
"typeVersion": 2.2
},
{
"id": "ad10f214-5653-4ce2-8934-a933723e984f",
"name": "Email Full Brief",
"type": "n8n-nodes-base.gmail",
"onError": "continueRegularOutput",
"position": [
3216,
592
],
"parameters": {
"sendTo": "={{ $json.alert_email || $vars.ALERT_EMAIL || 'alerts@company.com' }}",
"message": "=Pre-call Intelligence Brief\n\nProspect: {{ $json.prospect_name }}\nRole: {{ $json.current_role }}\nCompany: {{ $json.company }}\nMeeting Date: {{ $json.meeting_date }}\nReadiness Score: {{ $json.readiness_score }}/100\n\nCareer Trajectory:\n{{ $json.career_trajectory }}\n\nRecent Activity:\n{{ $json.recent_activity }}\n\nTalking Points:\n{{ Array.isArray($json.talking_points) ? $json.talking_points.join('\\n') : String($json.talking_points || 'N/A') }}\n\nPotential Pain Points:\n{{ Array.isArray($json.potential_pain_points) ? $json.potential_pain_points.join('\\n') : String($json.potential_pain_points || 'N/A') }}\n\nConnection Points: {{ $json.connection_points }}\nRecommended Approach: {{ $json.recommended_approach }}\nRisk Factors: {{ $json.risk_factors }}",
"options": {},
"subject": "=Pre-call brief: {{ $json.prospect_name }} at {{ $json.company }} (Ready: {{ $json.readiness_score }})",
"emailType": "text"
},
"typeVersion": 2.1
},
{
"id": "9501040b-97f6-45ee-99fe-408b5b352581",
"name": "Append Call Briefs",
"type": "n8n-nodes-base.googleSheets",
"onError": "continueRegularOutput",
"position": [
3424,
704
],
"parameters": {
"columns": {
"value": {},
"schema": [],
"mappingMode": "autoMapInputData",
"matchingColumns": []
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "call_briefs"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_SPREADSHEET_ID"
}
},
"typeVersion": 4.7
},
{
"id": "eb2b8d3e-52fa-49e8-b933-7311e173e4b1",
"name": "Email Short Brief",
"type": "n8n-nodes-base.gmail",
"onError": "continueRegularOutput",
"position": [
3136,
1200
],
"parameters": {
"sendTo": "={{ $json.alert_email || $vars.ALERT_EMAIL || 'alerts@company.com' }}",
"message": "=Pre-call Brief (Limited Data)\n\nProspect: {{ $json.prospect_name }}\nRole: {{ $json.current_role }}\nCompany: {{ $json.company }}\nMeeting Date: {{ $json.meeting_date }}\nReadiness Score: {{ $json.readiness_score }}/100\n\nNote: This prospect scored below 70 on readiness. Consider additional research before the call.\n\nCareer Trajectory:\n{{ $json.career_trajectory }}\n\nRecommended Approach: {{ $json.recommended_approach }}\nRisk Factors: {{ $json.risk_factors }}",
"options": {},
"subject": "=Pre-call brief (limited): {{ $json.prospect_name }} at {{ $json.company }}",
"emailType": "text"
},
"typeVersion": 2.1
},
{
"id": "6d93f04e-7e22-4909-888a-62e25b8a42ac",
"name": "Append Call Briefs Partial",
"type": "n8n-nodes-base.googleSheets",
"onError": "continueRegularOutput",
"position": [
3488,
992
],
"parameters": {
"columns": {
"value": {},
"schema": [],
"mappingMode": "autoMapInputData",
"matchingColumns": []
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "call_briefs"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_SPREADSHEET_ID"
}
},
"typeVersion": 4.7
},
{
"id": "f43d39e9-d277-4281-8dac-40e7f2bc34e7",
"name": "Append Low Confidence",
"type": "n8n-nodes-base.googleSheets",
"onError": "continueRegularOutput",
"position": [
2864,
1184
],
"parameters": {
"columns": {
"value": {},
"schema": [],
"mappingMode": "autoMapInputData",
"matchingColumns": []
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "low_confidence_briefs"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_SPREADSHEET_ID"
}
},
"typeVersion": 4.7
},
{
"id": "80150455-96f0-426d-8dea-d93c04e69d81",
"name": "Extract Key Talking Points",
"type": "n8n-nodes-base.code",
"position": [
1792,
944
],
"parameters": {
"jsCode": "// Extract key talking points and rapport hooks from LinkedIn profile data\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n const data = item.json;\n const profile = data.profile || data;\n \n const talking_points = [];\n const rapport_hooks = [];\n \n // Career trajectory analysis\n const experiences = profile.experiences || profile.experience || [];\n if (experiences.length >= 2) {\n const current = experiences[0];\n const previous = experiences[1];\n const trajectory = current.title && previous.title\n ? `Moved from ${previous.title} to ${current.title}`\n : null;\n if (trajectory) talking_points.push({ type: 'career_move', detail: trajectory });\n }\n \n // Current role tenure\n if (experiences.length > 0 && experiences[0].start_date) {\n const start = new Date(experiences[0].start_date);\n const months = Math.floor((Date.now() - start.getTime()) / (1000 * 60 * 60 * 24 * 30));\n if (months < 6) talking_points.push({ type: 'new_in_role', detail: `Started ${months} months ago - likely evaluating tools` });\n else if (months > 36) talking_points.push({ type: 'established', detail: `${months} months in role - focus on optimization pitch` });\n }\n \n // Education - shared alma mater potential\n const education = profile.education || [];\n for (const edu of education) {\n if (edu.school || edu.institution) {\n rapport_hooks.push({ type: 'education', school: edu.school || edu.institution, degree: edu.degree || '' });\n }\n }\n \n // Skills and endorsements - find tech stack overlap\n const skills = profile.skills || [];\n const tech_skills = skills.filter(s => {\n const name = (s.name || s || '').toLowerCase();\n return ['saas', 'cloud', 'api', 'data', 'analytics', 'automation', 'ai', 'machine learning'].some(k => name.includes(k));\n });\n if (tech_skills.length > 0) {\n talking_points.push({ type: 'tech_affinity', skills: tech_skills.slice(0, 5).map(s => s.name || s) });\n }\n \n // Recent activity themes\n const posts = profile.recent_posts || profile.posts || [];\n const post_topics = posts.slice(0, 5).map(p => p.title || p.text || '').filter(Boolean);\n if (post_topics.length > 0) {\n rapport_hooks.push({ type: 'recent_interests', topics: post_topics.slice(0, 3) });\n }\n \n // Connections count as social proof indicator\n const connections = profile.connections_count || profile.connections || 0;\n const influence_tier = connections > 5000 ? 'high' : connections > 1000 ? 'medium' : 'growing';\n \n results.push({\n json: {\n ...data,\n talking_points,\n rapport_hooks,\n prospect_profile: {\n influence_tier,\n connections_count: connections,\n talking_point_count: talking_points.length,\n rapport_hook_count: rapport_hooks.length\n }\n }\n });\n}\n\nreturn results;"
},
"typeVersion": 2
},
{
"id": "879566ab-2ac1-4115-982b-b03a385916b7",
"name": "Filter Valid Data",
"type": "n8n-nodes-base.if",
"onError": "continueErrorOutput",
"position": [
1536,
944
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "valid-check",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.status }}",
"rightValue": "ok"
}
]
}
},
"typeVersion": 2
},
{
"id": "50ad6b06-e8aa-47eb-b739-af18b0cb4e1b",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-224,
352
],
"parameters": {
"width": 560,
"height": 720,
"content": "### How it works\n\nThis automated LinkedIn intelligence pipeline scrapes data via Bright Data, analyzes it with GPT-5.5, and filters results by confidence and domain score before writing to Google Sheets. High-priority items trigger a Gmail alert.\n\n1. A schedule trigger reads URLs from a Google Sheet\n2. Each URL is sent to the Bright Data LinkedIn API\n3. Responses are validated for errors, empty results, and async snapshots\n4. GPT-5.5 analyzes the data and returns structured JSON with scores\n5. A confidence gate (>= 0.7) filters unreliable AI outputs\n6. Results route to: call_briefs, call_briefs, low_confidence_briefs\n\n### Setup\n\n1. Create a Google Sheet with a tab named 'upcoming_calls' and a 'url' column\n2. Add your Bright Data API key (HTTP Header Auth, Bearer token)\n3. Add your OpenAI API key\n4. Connect Google Sheets via OAuth\n5. Connect Gmail via OAuth for alerts\n\nCost: ~$0.01-0.03 per item (Bright Data) + ~$0.005 per analysis (GPT-5.5)"
},
"typeVersion": 1
},
{
"id": "06c1a0fb-9cde-42aa-9ce1-4ecca4903cce",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
480,
784
],
"parameters": {
"color": 7,
"height": 260,
"content": "## 1. Data Input\n\nReads LinkedIn URLs from the 'upcoming_calls' sheet."
},
"typeVersion": 1
},
{
"id": "500f2464-5d97-4839-9a58-710729a6d8d9",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
992,
784
],
"parameters": {
"color": 7,
"height": 292,
"content": "## 2. Data Collection\n\nSends each URL to the Bright Data LinkedIn API and validates the response."
},
"typeVersion": 1
},
{
"id": "f52ada1a-970f-4ba0-be52-1cb76e22f819",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
2000,
736
],
"parameters": {
"color": 7,
"width": 500,
"height": 532,
"content": "## 3. AI Analysis\n\nGPT-5.5 analyzes each item and returns structured JSON with scores and self-evaluation."
},
"typeVersion": 1
},
{
"id": "6d7d8edd-4f0d-4c4b-98ec-10f80f6e0819",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2544,
528
],
"parameters": {
"color": 7,
"width": 1636,
"height": 852,
"content": "## 4. Quality Gates & Output\n\nConfidence gate (>= 0.7) filters bad output. Domain gate: 'IF Readiness Score >= 70'. Routes to: call_briefs, call_briefs, low_confidence_briefs. Gmail alerts for flagged items."
},
"typeVersion": 1
}
],
"connections": {
"GPT-5.5 Model": {
"ai_languageModel": [
[
{
"node": "Build Call Brief",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Parse AI Output": {
"main": [
[
{
"node": "IF Confidence >= 0.7",
"type": "main",
"index": 0
}
]
]
},
"Build Call Brief": {
"main": [
[
{
"node": "Parse AI Output",
"type": "main",
"index": 0
}
]
]
},
"Filter Valid Data": {
"main": [
[
{
"node": "Extract Key Talking Points",
"type": "main",
"index": 0
}
]
]
},
"IF Confidence >= 0.7": {
"main": [
[
{
"node": "IF Readiness Score >= 70",
"type": "main",
"index": 0
}
],
[
{
"node": "Append Low Confidence",
"type": "main",
"index": 0
}
]
]
},
"Validate BD Response": {
"main": [
[
{
"node": "Filter Valid Data",
"type": "main",
"index": 0
}
]
]
},
"Daily Prospect Research": {
"main": [
[
{
"node": "Read Upcoming Calls Sheet",
"type": "main",
"index": 0
}
]
]
},
"Scrape LinkedIn Profile": {
"main": [
[
{
"node": "Validate BD Response",
"type": "main",
"index": 0
}
]
]
},
"IF Readiness Score >= 70": {
"main": [
[
{
"node": "Email Full Brief",
"type": "main",
"index": 0
},
{
"node": "Append Call Briefs",
"type": "main",
"index": 0
}
],
[
{
"node": "Email Short Brief",
"type": "main",
"index": 0
},
{
"node": "Append Call Briefs Partial",
"type": "main",
"index": 0
}
]
]
},
"Read Upcoming Calls Sheet": {
"main": [
[
{
"node": "Scrape LinkedIn Profile",
"type": "main",
"index": 0
}
]
]
},
"Extract Key Talking Points": {
"main": [
[
{
"node": "Build Call Brief",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automatically scrape LinkedIn profiles for upcoming sales calls, analyze the data with AI, score prospect readiness, and send structured pre-call briefs to your inbox.
Source: https://n8n.io/workflows/14986/ — 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 n8n automation workflow automates the creation, scripting, production, and posting of YouTube videos. It leverages AI (OpenAI), image generation (PIAPI), video rendering (Shotstack), and platform
Created by: Peyton Leveillee Last updated: October 2025
The Multi-Model Agency Content Engine is a high-performance editorial system designed for agencies. It solves the "blank page" problem by alternating between real-world social proof and strategic expe
This workflow automates the creation, rendering, approval, and posting of TikTok-style POV (Point of View) videos to Instagram, with cross-posting to Facebook and YouTube. It eliminates manual video p
SEO Blog Article Generation Workflow. Uses outputParserStructured, httpRequest, agent, lmChatOpenAi. Scheduled trigger; 56 nodes.