This workflow corresponds to n8n.io template #13185 — we link there as the canonical source.
This workflow follows the Agent → 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": "Vt9g1PaZtILHlmma",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "LinkedIn Post Scraping & Lead Intent Scorer",
"tags": [],
"nodes": [
{
"id": "9b77dd56-68b5-418c-a142-a3537374c6c7",
"name": "When clicking \u2018Execute workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-528,
1040
],
"parameters": {},
"typeVersion": 1
},
{
"id": "4ad7e46d-e4fd-4646-be54-70a2038a0c1a",
"name": "Main Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1104,
768
],
"parameters": {
"color": 4,
"width": 480,
"height": 824,
"content": "### How it works\n\nThis workflow scrapes LinkedIn posts that signal lead-generation pain points, extracts every comment on those posts, scores each commenter for buying intent using AI, and saves the ranked leads to a Google Sheet for follow-up.\n\n**Data flow:**\n1. A Google search (via SerpAPI) finds LinkedIn posts matching pain-point keywords such as \"missed leads\" or \"low conversion rate\".\n2. Raw search results are parsed and filtered to keep only valid LinkedIn post URLs.\n3. ConnectSafely fetches all comments on each post.\n4. Comments are flattened into individual rows.\n5. An AI agent (Azure OpenAI GPT-4o-mini) scores each comment on a 0\u2013100 intent scale.\n6. Parsed intent scores are appended to a Google Sheet.\n\n### Setup steps\n\n1. **SerpAPI** \u2013 Add your SerpAPI credential in the \"Search LinkedIn Posts\" node.\n2. **ConnectSafely** \u2013 Configure your ConnectSafely account credential (account ID required).\n3. **Azure OpenAI** \u2013 Add an Azure OpenAI credential with access to the gpt-4o-mini model.\n4. **Google Sheets** \u2013 Ensure the target sheet exists with columns: post_url, lead name, comment, intent score, intent label.\n\n### Customization\n\n- Edit the SerpAPI query keywords to target different pain points.\n- Adjust the intent-scoring prompt or thresholds inside the AI agent's system message.\n- Change the Google Sheet document ID or sheet name in the final node."
},
"typeVersion": 1
},
{
"id": "26b9f48a-b5fc-417a-ba77-58d3a685be55",
"name": "Section: Search & Scrape",
"type": "n8n-nodes-base.stickyNote",
"position": [
-560,
880
],
"parameters": {
"color": 5,
"width": 700,
"height": 116,
"content": "## Search & Scrape\n\nTriggers a Google search for pain-point posts on LinkedIn, parses the results, and fetches comments from each matched post via ConnectSafely."
},
"typeVersion": 1
},
{
"id": "f014517f-3998-4c2b-baa0-496b1be32683",
"name": "Section: Comment Processing",
"type": "n8n-nodes-base.stickyNote",
"position": [
192,
816
],
"parameters": {
"color": 5,
"width": 260,
"height": 196,
"content": "## Comment Processing\n\nReceives raw comment arrays from each post and flattens them into individual rows, one per commenter, ready for AI scoring."
},
"typeVersion": 1
},
{
"id": "64cea62a-6624-49b0-a2f1-41329dd61953",
"name": "Section: AI Intent Scoring",
"type": "n8n-nodes-base.stickyNote",
"position": [
496,
864
],
"parameters": {
"color": 5,
"width": 600,
"height": 100,
"content": "## AI Intent Scoring\n\nEach comment is analysed by an AI agent that returns a 0\u2013100 intent score and a label (no-intent \u2192 high-intent). Output is parsed into clean rows."
},
"typeVersion": 1
},
{
"id": "d3084ff1-14ff-4ad9-b601-bc923b41a772",
"name": "Warning: SerpAPI",
"type": "n8n-nodes-base.stickyNote",
"position": [
-336,
1248
],
"parameters": {
"color": 2,
"width": 268,
"height": 136,
"content": "\u26a0\ufe0f **SerpAPI Key Required**\n\nThis node calls the Google Search API. A valid SerpAPI credential must be configured, or every execution will fail at this step."
},
"typeVersion": 1
},
{
"id": "1a50334f-cfcb-41fe-8652-967df975a40e",
"name": "Warning: ConnectSafely",
"type": "n8n-nodes-base.stickyNote",
"position": [
80,
1216
],
"parameters": {
"color": 2,
"width": 252,
"height": 152,
"content": "\u26a0\ufe0f **ConnectSafely Credential Required**\n\nFetching post comments depends on an active ConnectSafely account. An invalid or expired API key will block the entire scrape."
},
"typeVersion": 1
},
{
"id": "5be1f1fb-c185-4d54-a2aa-6fe5674bae5d",
"name": "Warning: Azure OpenAI",
"type": "n8n-nodes-base.stickyNote",
"position": [
576,
1232
],
"parameters": {
"color": 2,
"width": 268,
"height": 152,
"content": "\u26a0\ufe0f **Azure OpenAI Credential Required**\n\nThe AI intent agent uses gpt-4o-mini. Ensure the Azure deployment name matches and the credential is active; otherwise scoring will fail."
},
"typeVersion": 1
},
{
"id": "1b825249-cc0d-46d5-9399-4b0a54e11f64",
"name": "Search LinkedIn Posts via SerpAPI",
"type": "n8n-nodes-serpapi.serpApi",
"position": [
-288,
1040
],
"parameters": {
"q": "site:linkedin.com/posts (\"Missed leads\" OR \"Losing leads\" OR \"Low conversion rate\" OR \"Leads not converting\")",
"requestOptions": {},
"additionalFields": {}
},
"credentials": {
"serpApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "8b562ae9-e9e4-4c5f-808f-6c627d9ac2b9",
"name": "Fetch Post Comments via ConnectSafely",
"type": "n8n-nodes-connectsafely-ai.connectSafelyLinkedIn",
"position": [
144,
1040
],
"parameters": {
"postUrl": "={{ $json.post_url }}",
"accountId": "695ce64a09c18d6bbbe90ed0",
"operation": "getAllPostComments"
},
"credentials": {
"connectSafelyApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "1d901be4-4abd-44ce-9c9d-7597381d84a8",
"name": "Parse & Filter Search Results",
"type": "n8n-nodes-base.code",
"position": [
-96,
1040
],
"parameters": {
"jsCode": "// ---------------------------\n// COLLECT ALL POSSIBLE RESULTS\n// ---------------------------\nconst data = items[0].json;\n\nconst results = [\n ...(data.organic_results || []),\n ...(data.inline_results || []),\n ...(data.discussions || []),\n ...(data.forums || []),\n];\n\nconst problemKeywords = [\n 'problem',\n 'issue',\n 'manual',\n 'not working',\n 'struggling',\n 'pain',\n 'challenge',\n 'empty',\n 'ghosted',\n 'ghosting',\n 'not enough',\n 'low',\n 'hard',\n 'difficult',\n 'miss',\n 'failing'\n];\n\nconst output = results.map(post => {\n const postUrl = post.link || '';\n let platform = 'Unknown';\n let username = null;\n let postId = null;\n let authorName = null;\n\n // ---------------------------\n // LINKEDIN DETECTION\n // ---------------------------\n if (/linkedin\\.com\\/posts\\//i.test(postUrl)) {\n platform = 'LinkedIn';\n\n const match = postUrl.match(/linkedin\\.com\\/posts\\/([^_]+).*?(\\d{8,})/i);\n if (match) {\n username = match[1];\n postId = match[2];\n }\n\n authorName = post.source\n ? post.source.replace('LinkedIn \u00b7 ', '').trim()\n : null;\n }\n\n // ---------------------------\n // REDDIT DETECTION (ROBUST)\n // ---------------------------\n if (/reddit\\.com/i.test(postUrl)) {\n platform = 'Reddit';\n\n const redditMatch = postUrl.match(\n /reddit\\.com\\/r\\/([^/]+)\\/comments\\/([^/]+)/i\n );\n\n if (redditMatch) {\n username = `r/${redditMatch[1]}`;\n postId = redditMatch[2];\n }\n\n authorName = post.source\n ? post.source.replace('Reddit \u00b7 ', '').trim()\n : username;\n }\n\n // ---------------------------\n // PROBLEM DETECTION\n // ---------------------------\n const text = `${post.title || ''} ${post.snippet || ''}`.toLowerCase();\n\n const detectedProblems = problemKeywords.filter(k =>\n text.includes(k)\n );\n\n return {\n json: {\n platform,\n author_name: authorName,\n username,\n post_id: postId,\n post_url: postUrl || null,\n post_title: post.title || null,\n post_snippet: post.snippet || null,\n engagement_hint: post.displayed_link || null,\n problem_keywords_detected: detectedProblems,\n is_problem_post: detectedProblems.length > 0\n }\n };\n});\n\n// REMOVE EMPTY / UNKNOWN URL RESULTS\nreturn output.filter(item => item.json.post_url);\n\n"
},
"typeVersion": 2
},
{
"id": "a77130f6-5705-4267-9ca7-5a80e17b68da",
"name": "AI Intent Detection Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
560,
1040
],
"parameters": {
"text": "=Analyze the following LinkedIn comment and identify lead intent.\n\nPost URL:\n{{ $json.postUrl }}\n\nPost Content:\n{{ $json.postContent }}\n\nCommenter Name:\n{{ $json.commenterName }}\n\nComment Text:\n{{ $json.commentText }}\n\nReturn the result in the following JSON format ONLY:\n\n{\n \"postUrl\": \"{{ $json.postUrl }}\",\n \"leadName\": \"{{ $json.commenterName }}\",\n \"comment\": \"{{ $json.commentText }}\",\n \"intentScore\": number,\n \"intentLabel\": \"no-intent | passive-interest | problem-aware | solution-aware | high-intent\"\n}\n",
"options": {
"systemMessage": "=You are a B2B sales intent detection agent.\n\nYour job is to analyze LinkedIn post context and comment text to identify whether the commenter shows buying intent, problem awareness, or decision-maker interest.\n\nYou must:\n- Use ONLY the data provided in the input\n- Infer intent from wording, tone, and relevance to the post\n- Be conservative: do not hallucinate intent\n- Prefer precision over recall\n\nScoring rules:\n- 0\u201320 \u2192 No intent (generic praise, agreement, emojis)\n- 21\u201340 \u2192 Passive interest (thoughtful comment, but no problem ownership)\n- 41\u201360 \u2192 Problem-aware (mentions pain points, challenges, or agreement with problem)\n- 61\u201380 \u2192 Solution-aware (implies need for solution, improvement, or optimization)\n- 81\u2013100 \u2192 High buying intent (clear ownership, decision role, desire to act)\n\nIf intent is below 30, still return the record but mark it as \"low-intent\".\n\nOutput MUST be valid JSON and follow the exact schema provided.\nDo not add explanations or extra text.\n"
},
"promptType": "define"
},
"typeVersion": 3
},
{
"id": "9ccedfae-79a5-402a-85d3-554cee94fae4",
"name": "Azure OpenAI GPT-4o-mini",
"type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
"position": [
432,
1248
],
"parameters": {
"model": "gpt-4o-mini",
"options": {}
},
"credentials": {
"azureOpenAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "64643688-528f-456d-aaec-e19baff2137f",
"name": "Flatten Comments into Rows",
"type": "n8n-nodes-base.code",
"position": [
352,
1040
],
"parameters": {
"jsCode": "const results = [];\n\nfor (const item of items) {\n const post = item.json;\n\n const postUrl = post.postUrl || '';\n const postContent = post.postDetails?.content || '';\n const activityUrn = post.postDetails?.activityUrn || null;\n\n const comments = post.comments || [];\n\n for (const comment of comments) {\n results.push({\n json: {\n // Post info\n postUrl,\n activityUrn,\n postContent,\n\n // Comment info\n commentId: comment.commentId,\n commentText: comment.commentText,\n commenterName: comment.authorName,\n commenterProfileUrl: comment.profileUrl || null,\n commenterUrn: comment.commenterUrn || null,\n\n // Metadata\n createdAt: comment.createdAt,\n likeCount: comment.likeCount,\n replyCount: comment.replyCount,\n isProfile: comment.hasProfile\n }\n });\n }\n}\n\nreturn results;\n"
},
"typeVersion": 2
},
{
"id": "27741bee-6896-460a-8bb2-333065225462",
"name": "Parse AI Intent Output",
"type": "n8n-nodes-base.code",
"position": [
912,
1040
],
"parameters": {
"jsCode": "const results = [];\n\nfor (const item of items) {\n // Skip empty or invalid outputs safely\n if (!item.json.output) continue;\n\n let parsed;\n try {\n parsed = JSON.parse(item.json.output);\n } catch (e) {\n // If parsing fails, skip this record\n continue;\n }\n\n results.push({\n json: {\n postUrl: parsed.postUrl || null,\n leadName: parsed.leadName || null,\n comment: parsed.comment || null,\n intentScore: parsed.intentScore ?? null,\n intentLabel: parsed.intentLabel || null\n }\n });\n}\n\nreturn results;\n"
},
"typeVersion": 2
},
{
"id": "1d190ab7-11b2-40db-bc24-a7a2f16df196",
"name": "Save Leads to Google Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
1136,
1040
],
"parameters": {
"columns": {
"value": {
"comment": "={{ $json.comment }}",
"post_url": "={{ $json.postUrl }}",
"lead name": "={{ $json.leadName }}",
"intent label": "={{ $json.intentLabel }}",
"intent score": "={{ $json.intentScore }}"
},
"schema": [
{
"id": "post_url",
"type": "string",
"display": true,
"required": false,
"displayName": "post_url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lead name",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lead name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "comment",
"type": "string",
"display": true,
"required": false,
"displayName": "comment",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "intent score",
"type": "string",
"display": true,
"required": false,
"displayName": "intent score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "intent label",
"type": "string",
"display": true,
"required": false,
"displayName": "intent label",
"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/1hXDNE90IFbXLgyLt2XwSHgI_9sASzTSM9LAA4cUDFj4/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1hXDNE90IFbXLgyLt2XwSHgI_9sASzTSM9LAA4cUDFj4",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hXDNE90IFbXLgyLt2XwSHgI_9sASzTSM9LAA4cUDFj4/edit?usp=drivesdk",
"cachedResultName": "Post Scraping"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "3c109119-fdf5-4216-92ef-7f00bbde7c2f",
"connections": {
"Parse AI Intent Output": {
"main": [
[
{
"node": "Save Leads to Google Sheet",
"type": "main",
"index": 0
}
]
]
},
"Azure OpenAI GPT-4o-mini": {
"ai_languageModel": [
[
{
"node": "AI Intent Detection Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"AI Intent Detection Agent": {
"main": [
[
{
"node": "Parse AI Intent Output",
"type": "main",
"index": 0
}
]
]
},
"Flatten Comments into Rows": {
"main": [
[
{
"node": "AI Intent Detection Agent",
"type": "main",
"index": 0
}
]
]
},
"Parse & Filter Search Results": {
"main": [
[
{
"node": "Fetch Post Comments via ConnectSafely",
"type": "main",
"index": 0
}
]
]
},
"Search LinkedIn Posts via SerpAPI": {
"main": [
[
{
"node": "Parse & Filter Search Results",
"type": "main",
"index": 0
}
]
]
},
"When clicking \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "Search LinkedIn Posts via SerpAPI",
"type": "main",
"index": 0
}
]
]
},
"Fetch Post Comments via ConnectSafely": {
"main": [
[
{
"node": "Flatten Comments into Rows",
"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.
azureOpenAiApiconnectSafelyApigoogleSheetsOAuth2ApiserpApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automate LinkedIn lead discovery by identifying high-intent prospects directly from post comments using ConnectSafely and AI 🤖. This workflow searches LinkedIn posts related to common sales pain points, extracts all comments safely, and evaluates each commenter’s buying intent…
Source: https://n8n.io/workflows/13185/ — 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 workflow is designed for marketers, content creators, agencies, and solo founders who want to publish long‑form posts with visuals on autopilot using n8n and AI agents.
This workflow is for job seekers who want to automate their entire application pipeline — from discovering job postings to generating personalized cover letters, CVs, and organizing everything in Goog
Automate your AI-powered outreach and follow-up pipeline end-to-end with GPT-4o, Gmail, and Google Sheets. 🤖📬 This workflow personalizes emails for each lead, manages follow-ups automatically, tracks
Automatically compare candidate resumes to job descriptions (PDFs) from Google Drive, generate a 0–100 fit score with gap analysis, and update Google Sheets—powered by Azure OpenAI (GPT-4o-mini). Fast
This workflow intelligently analyzes incoming Gmail emails, classifies intent using GPT-4, and sends real-time Slack notifications while logging structured data into Google Sheets. It provides a smart