← All Guides
Social Intermediate 7 min read

LinkedIn Social Listening Workflow

Build an n8n workflow that monitors LinkedIn for keywords, scores relevance with AI, and sends draft replies to Telegram.

n8nApifyOpenRouter

What We’re Building

A fully automated LinkedIn social listening system that:

  1. Scrapes LinkedIn for posts matching your target keywords (via Apify)
  2. Scores each post for relevance using an AI model (via OpenRouter)
  3. Drafts a personalized reply for high-scoring posts
  4. Sends alerts to Telegram with the post, score, and draft reply — ready for you to copy-paste

The end result: you wake up to a Telegram channel full of pre-written, context-aware replies to the most relevant LinkedIn conversations in your niche. No scrolling required.

Initial Prompt

“I want to monitor LinkedIn for posts about AI automation, score them for relevance to Happy Operators, and get draft replies sent to my Telegram. Use n8n, Apify for scraping, and OpenRouter for the AI scoring.”

Architecture Overview

ComponentToolPurpose
Schedulern8n CronTriggers the workflow daily at 7am
ScraperApify LinkedIn ActorSearches LinkedIn for keyword matches
Filtern8n Code NodeDeduplicates and cleans raw results
AI ScorerOpenRouter (Claude/GPT)Scores relevance 1-10 with reasoning
Reply DrafterOpenRouter (Claude/GPT)Writes personalized reply drafts
NotificationTelegram Bot APISends formatted alerts to your channel

Flow:

Cron (7am) → Apify Search → Filter & Dedupe → AI Score → Draft Reply → Telegram

Step-by-Step Build

Step 1: Set Up Apify LinkedIn Scraper

First, you need an Apify account and a LinkedIn scraping actor.

  1. Sign up at apify.com (free tier works for low volume)
  2. Find the LinkedIn Posts Search actor in the Apify Store
  3. Configure it with your search keywords:
{
  "searchKeywords": ["AI automation", "workflow automation", "n8n"],
  "maxResults": 50,
  "timeFilter": "past-24h",
  "sortBy": "relevance"
}
  1. Run it once manually to verify results
  2. Copy your API token from Apify Settings — you’ll need this in n8n

Step 2: Create the n8n Workflow

Open your n8n instance and create a new workflow.

Trigger Node: Schedule

{
  "rule": {
    "interval": [{ "field": "cronExpression", "expression": "0 7 * * *" }]
  }
}

This fires every day at 7:00 AM.

HTTP Request Node: Call Apify

Add an HTTP Request node to trigger the Apify actor:

Method: POST
URL: https://api.apify.com/v2/acts/YOUR_ACTOR_ID/runs
Headers:
  Authorization: Bearer YOUR_APIFY_TOKEN
  Content-Type: application/json
Body:
{
  "searchKeywords": ["AI automation", "workflow automation"],
  "maxResults": 50,
  "timeFilter": "past-24h"
}

Wait Node

Apify runs are async. Add a Wait node (60-120 seconds) for the scrape to complete, then fetch results:

Method: GET
URL: https://api.apify.com/v2/actor-runs/{{ $json.data.id }}/dataset/items
Headers:
  Authorization: Bearer YOUR_APIFY_TOKEN

Step 3: Filter & Deduplicate

Add a Code node to clean the results:

const items = $input.all();
const seen = new Set();
const filtered = [];

for (const item of items) {
  const post = item.json;

  // Skip if we've seen this post URL before
  if (seen.has(post.url)) continue;
  seen.add(post.url);

  // Skip posts with very low engagement
  if ((post.likes || 0) < 5) continue;

  // Skip your own posts
  if (post.authorName?.includes('Happy Operators')) continue;

  filtered.push({
    json: {
      url: post.url,
      author: post.authorName,
      authorHeadline: post.authorHeadline,
      content: post.text?.substring(0, 1000), // Truncate for AI
      likes: post.likes || 0,
      comments: post.comments || 0,
      postedAt: post.postedAt,
    }
  });
}

return filtered;

Step 4: AI Relevance Scoring

Add an HTTP Request node to call OpenRouter:

Method: POST
URL: https://openrouter.ai/api/v1/chat/completions
Headers:
  Authorization: Bearer YOUR_OPENROUTER_KEY
  Content-Type: application/json

Request body:

{
  "model": "anthropic/claude-sonnet-4-5-20250929",
  "messages": [
    {
      "role": "system",
      "content": "You are a social listening analyst for Happy Operators, an AI & automation training company. Score LinkedIn posts for engagement relevance on a scale of 1-10.\n\nScore HIGH (7-10) if the post:\n- Discusses AI/automation pain points we solve\n- Is from a founder, ops lead, or team manager\n- Has good engagement (likes/comments)\n- Offers a natural opening for our expertise\n\nScore LOW (1-3) if the post:\n- Is from a competitor selling similar services\n- Is purely self-promotional with no conversation\n- Is off-topic (just mentions AI tangentially)\n\nRespond in JSON: {\"score\": N, \"reason\": \"brief explanation\", \"angle\": \"suggested approach for reply\"}"
    },
    {
      "role": "user",
      "content": "Author: {{ $json.author }}\nHeadline: {{ $json.authorHeadline }}\nPost: {{ $json.content }}\nEngagement: {{ $json.likes }} likes, {{ $json.comments }} comments"
    }
  ],
  "temperature": 0.3
}

Parse the response with a Code node:

const response = JSON.parse($input.first().json.choices[0].message.content);
return [{
  json: {
    ...$input.first().json,
    score: response.score,
    reason: response.reason,
    angle: response.angle,
  }
}];

Step 5: Filter High-Score Posts

Add an IF node:

Condition: {{ $json.score }} >= 7

Only posts scoring 7+ continue to the reply drafting step.

Step 6: Draft Replies

Another OpenRouter call to draft the actual reply:

{
  "model": "anthropic/claude-sonnet-4-5-20250929",
  "messages": [
    {
      "role": "system",
      "content": "Write a LinkedIn comment reply for Happy Operators. Rules:\n- Be genuinely helpful, not salesy\n- Reference something specific from the post\n- Add a practical insight or tip\n- Keep it under 100 words\n- Sound human, not corporate\n- No emojis in the first line\n- End with a question or conversation opener when natural"
    },
    {
      "role": "user",
      "content": "Post by {{ $json.author }}:\n{{ $json.content }}\n\nSuggested angle: {{ $json.angle }}"
    }
  ],
  "temperature": 0.7
}

Step 7: Send to Telegram

Final node — send the formatted alert:

Method: POST
URL: https://api.telegram.org/bot{{ YOUR_BOT_TOKEN }}/sendMessage
Body:
{
  "chat_id": "YOUR_CHAT_ID",
  "parse_mode": "HTML",
  "text": "🎯 <b>LinkedIn Match (Score: {{ $json.score }}/10)</b>\n\n<b>Author:</b> {{ $json.author }}\n<b>Why:</b> {{ $json.reason }}\n\n<b>Post preview:</b>\n<i>{{ $json.content.substring(0, 300) }}...</i>\n\n<b>Draft reply:</b>\n{{ $json.draftReply }}\n\n<a href=\"{{ $json.url }}\">Open on LinkedIn →</a>"
}

Setup Checklist

Before running this workflow, you need:

  • Apify account with LinkedIn Posts Search actor — apify.com
  • Apify API token — Settings → Integrations
  • OpenRouter account with credits — openrouter.ai
  • OpenRouter API key — Keys section in dashboard
  • Telegram Bot — create via @BotFather
  • Telegram Chat ID — send a message to your bot, then call getUpdates API
  • n8n instance — self-hosted or n8n.io cloud
  • Keywords defined — what topics should trigger monitoring

How to Use

Once deployed, the workflow runs automatically every morning:

  1. Check Telegram — you’ll have a channel of scored, filtered LinkedIn posts with draft replies
  2. Review the drafts — adjust tone or add personal context if needed
  3. Copy-paste to LinkedIn — open the post link, paste the reply, send
  4. Track what works — note which scores/angles lead to actual conversations

Tips for best results:

  • Start with 3-5 specific keywords, not broad terms
  • Adjust the scoring prompt as you learn what “relevant” means for your business
  • Review and skip posts scored 7 that aren’t actually useful — refine the prompt
  • Aim to respond within 2-4 hours of the post going live for maximum visibility

Future Improvements

  • LinkedIn comment posting — auto-post approved replies (requires LinkedIn API access or browser automation)
  • CRM integration — auto-create leads in Notion when you engage with someone
  • Engagement tracking — follow up on posts you replied to, track if they responded
  • Multi-platform — extend to Twitter/X with similar scoring
  • Sentiment analysis — detect frustration posts (higher conversion opportunity)
  • Slack alternative — send to Slack instead of or alongside Telegram

Need help building this?

We build workflows like this for teams every week. Book a free discovery call and we'll scope it together.

Chat with us →