AutomationFlowsAI & RAG › Monitor Brand Mentions on X, Reddit & News

Monitor Brand Mentions on X, Reddit & News

Original n8n title: Monitor Brand Mentions with Openai Across Twitter/x, Reddit, News, Airtable and Slack

ByOneclick AI Squad @oneclick-ai on n8n.io

Monitors brand mentions across Twitter/X, Reddit, and News APIs in real-time (or scheduled), fetches mentions in parallel, normalizes data, uses AI to analyze sentiment/urgency/topics, detects duplicates, filters critical mentions, logs everything to Airtable, posts alerts to…

Cron / scheduled trigger★★★★☆ complexity23 nodesHTTP RequestEmail Send
AI & RAG Trigger: Cron / scheduled Nodes: 23 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #13653 — we link there as the canonical source.

This workflow follows the Emailsend → HTTP Request 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 →

Download .json
{
  "id": "am1RwBADxjmSSZRZ",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "AI Social Listening Agent",
  "tags": [],
  "nodes": [
    {
      "id": "7c80824c-f381-4551-a857-74c7cd35337d",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2752,
        -464
      ],
      "parameters": {
        "width": 820,
        "height": 720,
        "content": "## AI Social Listening Agent\n\nMonitors brand mentions across Twitter/X, Reddit, and news sources in real-time. Uses AI to analyze sentiment (positive/negative/neutral), detects trending topics, classifies urgency, and delivers actionable insights via Slack and Email with daily digest reports.\n\n## How it works\n\n1. **Trigger** \u2014 Runs every hour to check for new brand mentions\n2. **Fetch & collect** \u2014 Pulls mentions from Twitter/X, Reddit, and News APIs in parallel\n3. **Analyze** \u2014 AI sentiment analysis, urgency classification, and trend detection\n4. **Deduplicate** \u2014 Filters already-processed mentions to avoid noise\n5. **Alert** \u2014 Sends real-time Slack alerts for negative/urgent mentions; logs all to Airtable\n6. **Report** \u2014 Generates daily HTML digest and emails summary to marketing team\n\n## Setup steps\n\n1. **Social APIs** \u2014 Add your Twitter/X Bearer Token, Reddit Client ID/Secret, and News API Key\n2. **OpenAI** \u2014 Add your OpenAI API key for sentiment analysis\n3. **Airtable** \u2014 Create a `brand_mentions` base and add your API key\n4. **Slack** \u2014 Add your incoming webhook URL to the Slack node\n5. **Email** \u2014 Configure SMTP credentials and set `from` / `to` addresses\n6. **Brand Config** \u2014 Update the brand name and keywords in the Config node\n7. **Test** \u2014 Run manually to verify all connections, then activate"
      },
      "typeVersion": 1
    },
    {
      "id": "43b61124-1746-4b60-9632-91ef576a8de4",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1840,
        -368
      ],
      "parameters": {
        "color": 5,
        "width": 468,
        "height": 465,
        "content": "## 1. Trigger & configure\n\nRuns every hour to initiate brand monitoring. Config node sets brand name, keywords, and monitoring parameters"
      },
      "typeVersion": 1
    },
    {
      "id": "875435b7-441a-46b2-a86f-1ccfced6b2a3",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1328,
        -496
      ],
      "parameters": {
        "color": 5,
        "width": 668,
        "height": 820,
        "content": "## 2. Fetch & collect mentions\n\nFetches brand mentions from Twitter/X, Reddit, and News APIs in parallel, then merges all results into a unified stream"
      },
      "typeVersion": 1
    },
    {
      "id": "67f60b4a-55fc-4e5e-9200-2553a772f960",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -624,
        -544
      ],
      "parameters": {
        "color": 5,
        "width": 588,
        "height": 905,
        "content": "## 3. AI analyze & deduplicate\n\nUses OpenAI to classify sentiment, detect urgency, extract topics, and deduplicates mentions already seen this session"
      },
      "typeVersion": 1
    },
    {
      "id": "62d00e40-ad6e-458e-8ef6-13793c17d173",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        32,
        -528
      ],
      "parameters": {
        "color": 5,
        "width": 1328,
        "height": 713,
        "content": "## 4. Store, alert & report\n\nLogs all mentions to Airtable, sends real-time Slack alerts for negative/urgent mentions, and emails a daily HTML digest to the marketing team"
      },
      "typeVersion": 1
    },
    {
      "id": "28fbfdd8-4086-47b1-a30d-eaf8b80d5d54",
      "name": "Monitor brand mentions every hour",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1712,
        -64
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "39123f7b-7809-4887-bdf8-9105af94f0f7",
      "name": "Set brand monitoring config",
      "type": "n8n-nodes-base.set",
      "position": [
        -1488,
        -64
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "brand-name",
              "name": "brandName",
              "type": "string",
              "value": "YourBrand"
            },
            {
              "id": "keywords",
              "name": "keywords",
              "type": "string",
              "value": "YourBrand,@YourBrand,#YourBrand"
            },
            {
              "id": "lookback-hours",
              "name": "lookbackHours",
              "type": "number",
              "value": 1
            },
            {
              "id": "alert-threshold",
              "name": "negativeAlertThreshold",
              "type": "number",
              "value": 3
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "dbac966d-a71b-4dc9-84b3-621beca97b98",
      "name": "Fetch Twitter/X mentions",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1264,
        -352
      ],
      "parameters": {
        "url": "https://api.twitter.com/2/tweets/search/recent",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "query",
              "value": "={{ $json.brandName + ' -is:retweet lang:en' }}"
            },
            {
              "name": "tweet.fields",
              "value": "created_at,author_id,text,public_metrics,geo"
            },
            {
              "name": "max_results",
              "value": "50"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "f3a1d9e5-14e8-4b1c-a04c-57a23f5cd2a4",
      "name": "Fetch Reddit mentions",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1264,
        -160
      ],
      "parameters": {
        "url": "https://www.reddit.com/search.json",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ $json.brandName }}"
            },
            {
              "name": "sort",
              "value": "new"
            },
            {
              "name": "t",
              "value": "day"
            },
            {
              "name": "limit",
              "value": "25"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "d6f98d40-927b-41b0-bd18-5246780b10b8",
      "name": "Fetch news article mentions",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1264,
        32
      ],
      "parameters": {
        "url": "https://newsapi.org/v2/everything",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ $json.brandName }}"
            },
            {
              "name": "sortBy",
              "value": "publishedAt"
            },
            {
              "name": "language",
              "value": "en"
            },
            {
              "name": "pageSize",
              "value": "20"
            },
            {
              "name": "apiKey",
              "value": "YOUR_NEWS_API_KEY"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "0a3f264c-b449-41de-822f-888ac8b0e899",
      "name": "Merge all platform mentions",
      "type": "n8n-nodes-base.merge",
      "position": [
        -1040,
        -160
      ],
      "parameters": {
        "mode": "combine",
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "81837c5d-634f-4019-8195-46fc6268d41c",
      "name": "Normalize mentions into unified schema",
      "type": "n8n-nodes-base.code",
      "position": [
        -816,
        -160
      ],
      "parameters": {
        "jsCode": "// Normalize all platform data into a unified mention schema\nconst items = $input.all();\nconst normalizedMentions = [];\nconst now = new Date();\nconst brandName = 'YourBrand'; // Update to match config\n\nitems.forEach(item => {\n  const data = item.json;\n\n  // Twitter/X mentions\n  if (data.data && Array.isArray(data.data)) {\n    data.data.forEach(tweet => {\n      normalizedMentions.push({\n        platform: 'Twitter/X',\n        mentionId: `tw_${tweet.id}`,\n        text: tweet.text || '',\n        author: tweet.author_id || 'unknown',\n        url: `https://twitter.com/i/web/status/${tweet.id}`,\n        publishedAt: tweet.created_at || now.toISOString(),\n        likes: tweet.public_metrics?.like_count || 0,\n        shares: tweet.public_metrics?.retweet_count || 0,\n        reach: (tweet.public_metrics?.like_count || 0) + (tweet.public_metrics?.retweet_count || 0),\n        rawData: tweet\n      });\n    });\n  }\n\n  // Reddit mentions\n  if (data.data?.children && Array.isArray(data.data.children)) {\n    data.data.children.forEach(post => {\n      const p = post.data;\n      normalizedMentions.push({\n        platform: 'Reddit',\n        mentionId: `rd_${p.id}`,\n        text: `${p.title} ${p.selftext || ''}`.trim(),\n        author: p.author || 'unknown',\n        url: `https://reddit.com${p.permalink}`,\n        publishedAt: new Date(p.created_utc * 1000).toISOString(),\n        likes: p.score || 0,\n        shares: p.num_comments || 0,\n        reach: p.score || 0,\n        rawData: p\n      });\n    });\n  }\n\n  // News mentions\n  if (data.articles && Array.isArray(data.articles)) {\n    data.articles.forEach((article, idx) => {\n      normalizedMentions.push({\n        platform: 'News',\n        mentionId: `nw_${Buffer.from(article.url || idx.toString()).toString('base64').slice(0,12)}`,\n        text: `${article.title} ${article.description || ''}`.trim(),\n        author: article.source?.name || 'Unknown Source',\n        url: article.url || '',\n        publishedAt: article.publishedAt || now.toISOString(),\n        likes: 0,\n        shares: 0,\n        reach: 0,\n        rawData: article\n      });\n    });\n  }\n});\n\nconst reportTimestamp = now.toISOString();\nconst reportDate = now.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });\n\nreturn normalizedMentions.map(mention => ({\n  json: {\n    ...mention,\n    brandName,\n    reportTimestamp,\n    reportDate,\n    totalMentionsCollected: normalizedMentions.length\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "c5e986df-9285-4d2b-b43f-4ea0f4569d8d",
      "name": "AI sentiment and urgency analysis",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -592,
        -160
      ],
      "parameters": {
        "url": "https://api.openai.com/v1/chat/completions",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"model\": \"gpt-4o-mini\",\n  \"max_tokens\": 300,\n  \"response_format\": { \"type\": \"json_object\" },\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"You are a brand monitoring AI. Analyze the given text and return ONLY valid JSON with these fields: sentiment (positive/negative/neutral), sentimentScore (-1.0 to 1.0), urgency (low/medium/high/critical), topics (array of up to 3 key topics), summary (one sentence), requiresResponse (boolean), language (ISO 639-1 code).\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \"Analyze this brand mention from {{ $json.platform }}: {{ $json.text }}\"\n    }\n  ]\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "11463390-874b-43e1-ab29-1b5dc31f4b76",
      "name": "Process AI analysis results",
      "type": "n8n-nodes-base.code",
      "position": [
        -160,
        -160
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Parse AI response and enrich mention with sentiment data\nconst item = $input.item.json;\n\nlet aiAnalysis = {};\ntry {\n  const content = item.choices?.[0]?.message?.content || '{}';\n  aiAnalysis = JSON.parse(content);\n} catch (e) {\n  aiAnalysis = {\n    sentiment: 'neutral',\n    sentimentScore: 0,\n    urgency: 'low',\n    topics: [],\n    summary: 'Analysis unavailable',\n    requiresResponse: false,\n    language: 'en'\n  };\n}\n\nconst sentiment = aiAnalysis.sentiment || 'neutral';\nconst urgency = aiAnalysis.urgency || 'low';\n\n// Generate mention ID for dedup tracking\nconst mentionId = item.mentionId || `gen_${Date.now()}`;\n\n// Check duplicate via static data\nconst processedMentions = $getWorkflowStaticData('global').processedMentions || {};\nconst isDuplicate = !!processedMentions[mentionId];\n\nif (!isDuplicate) {\n  processedMentions[mentionId] = {\n    timestamp: new Date().toISOString(),\n    sentiment,\n    urgency\n  };\n  // Clean up mentions older than 7 days\n  const sevenDaysAgo = Date.now() - (7 * 24 * 60 * 60 * 1000);\n  for (const key in processedMentions) {\n    if (new Date(processedMentions[key].timestamp).getTime() < sevenDaysAgo) {\n      delete processedMentions[key];\n    }\n  }\n  $getWorkflowStaticData('global').processedMentions = processedMentions;\n}\n\n// Update cumulative stats\nconst stats = $getWorkflowStaticData('global').mentionStats || {\n  total: 0, positive: 0, negative: 0, neutral: 0, critical: 0, byPlatform: {}\n};\nif (!isDuplicate) {\n  stats.total++;\n  if (sentiment === 'positive') stats.positive++;\n  else if (sentiment === 'negative') stats.negative++;\n  else stats.neutral++;\n  if (urgency === 'critical') stats.critical++;\n  stats.byPlatform[item.platform] = (stats.byPlatform[item.platform] || 0) + 1;\n  $getWorkflowStaticData('global').mentionStats = stats;\n}\n\nconst requiresAlert = (sentiment === 'negative' && urgency !== 'low') || urgency === 'critical';\n\nreturn {\n  json: {\n    ...item,\n    mentionId,\n    sentiment,\n    sentimentScore: aiAnalysis.sentimentScore || 0,\n    urgency,\n    topics: aiAnalysis.topics || [],\n    aiSummary: aiAnalysis.summary || '',\n    requiresResponse: aiAnalysis.requiresResponse || false,\n    language: aiAnalysis.language || 'en',\n    isDuplicate,\n    requiresAlert,\n    processedAt: new Date().toISOString()\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "d74607a5-73b7-48ae-90fa-5ef7f0b2722c",
      "name": "Route by sentiment and urgency",
      "type": "n8n-nodes-base.switch",
      "position": [
        64,
        -176
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Critical \u2014 Immediate Alert",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.urgency }}",
                    "rightValue": "critical"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Negative \u2014 Needs Attention",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.sentiment }}",
                    "rightValue": "negative"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Positive or Neutral",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "or",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.sentiment }}",
                    "rightValue": "positive"
                  },
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.sentiment }}",
                    "rightValue": "neutral"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "56f4a0f6-87ae-48b3-8c63-356a4938a057",
      "name": "Send critical mention alert",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        288,
        -352
      ],
      "parameters": {
        "url": "https://api.example.com/alerts/send",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "alert_type",
              "value": "CRITICAL_BRAND_MENTION"
            },
            {
              "name": "severity",
              "value": "critical"
            },
            {
              "name": "platform",
              "value": "={{ $json.platform }}"
            },
            {
              "name": "mention_id",
              "value": "={{ $json.mentionId }}"
            },
            {
              "name": "sentiment",
              "value": "={{ $json.sentiment }}"
            },
            {
              "name": "message",
              "value": "={{ 'CRITICAL brand mention on ' + $json.platform + ': ' + $json.aiSummary + ' \u2014 URL: ' + $json.url }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "bcc14722-99ac-42a7-8558-63db38e82b2c",
      "name": "Log mention to Airtable",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        288,
        -160
      ],
      "parameters": {
        "url": "https://api.airtable.com/v0/YOUR_BASE_ID/brand_mentions",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"fields\": {\n    \"Mention ID\": \"{{ $json.mentionId }}\",\n    \"Platform\": \"{{ $json.platform }}\",\n    \"Text\": \"{{ $json.text.slice(0, 500) }}\",\n    \"Author\": \"{{ $json.author }}\",\n    \"URL\": \"{{ $json.url }}\",\n    \"Sentiment\": \"{{ $json.sentiment }}\",\n    \"Sentiment Score\": {{ $json.sentimentScore }},\n    \"Urgency\": \"{{ $json.urgency }}\",\n    \"Topics\": \"{{ $json.topics.join(', ') }}\",\n    \"AI Summary\": \"{{ $json.aiSummary }}\",\n    \"Requires Response\": {{ $json.requiresResponse }},\n    \"Published At\": \"{{ $json.publishedAt }}\",\n    \"Processed At\": \"{{ $json.processedAt }}\",\n    \"Is Duplicate\": {{ $json.isDuplicate }},\n    \"Reach\": {{ $json.reach }}\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "06e26387-1dc9-46c9-9af2-41b4f73509fb",
      "name": "Generate HTML daily digest report",
      "type": "n8n-nodes-base.code",
      "position": [
        512,
        -240
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Generate HTML daily digest report for brand mentions\nconst mention = $input.item.json;\nconst stats = $getWorkflowStaticData('global').mentionStats || { total: 0, positive: 0, negative: 0, neutral: 0, critical: 0, byPlatform: {} };\n\nconst sentimentColor = mention.sentiment === 'positive' ? '#22c55e' : mention.sentiment === 'negative' ? '#ef4444' : '#94a3b8';\nconst urgencyColor = mention.urgency === 'critical' ? '#ef4444' : mention.urgency === 'high' ? '#f97316' : mention.urgency === 'medium' ? '#f59e0b' : '#22c55e';\nconst sentimentIcon = mention.sentiment === 'positive' ? '\ud83d\ude0a' : mention.sentiment === 'negative' ? '\ud83d\ude20' : '\ud83d\ude10';\n\nconst platformRows = Object.entries(stats.byPlatform).map(([p, count]) => `<tr><td>${p}</td><td>${count}</td></tr>`).join('') || '<tr><td colspan=\"2\">No data yet</td></tr>';\n\nconst positiveRate = stats.total > 0 ? Math.round((stats.positive / stats.total) * 100) : 0;\nconst negativeRate = stats.total > 0 ? Math.round((stats.negative / stats.total) * 100) : 0;\nconst neutralRate = stats.total > 0 ? Math.round((stats.neutral / stats.total) * 100) : 0;\n\nconst reportHtml = `\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Brand Mention Digest \u2014 ${mention.reportDate}</title>\n  <style>\n    body { font-family: Arial, sans-serif; color: #1e293b; margin: 0; padding: 24px; background: #f8fafc; }\n    .header { background: #0f172a; color: white; padding: 24px; border-radius: 8px; margin-bottom: 24px; }\n    .header h1 { margin: 0 0 8px 0; font-size: 22px; }\n    .header p { margin: 0; opacity: 0.7; font-size: 13px; }\n    .badge { display: inline-block; padding: 6px 16px; border-radius: 20px; font-weight: bold; font-size: 14px; background: ${sentimentColor}; color: white; margin-top: 12px; }\n    .cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 24px; }\n    .card { background: white; border-radius: 8px; padding: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n    .card .value { font-size: 28px; font-weight: bold; }\n    .card .label { font-size: 12px; color: #64748b; margin-top: 4px; }\n    .section { background: white; border-radius: 8px; padding: 20px; margin-bottom: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n    .section h2 { margin: 0 0 16px 0; font-size: 16px; border-bottom: 2px solid #e2e8f0; padding-bottom: 8px; }\n    table { width: 100%; border-collapse: collapse; font-size: 13px; }\n    th { background: #f1f5f9; text-align: left; padding: 8px 12px; }\n    td { padding: 8px 12px; border-bottom: 1px solid #e2e8f0; }\n    .mention-card { border-left: 4px solid ${sentimentColor}; padding: 12px 16px; background: #f8fafc; border-radius: 4px; margin-bottom: 8px; }\n    .footer { text-align: center; font-size: 11px; color: #94a3b8; margin-top: 24px; }\n  </style>\n</head>\n<body>\n  <div class=\"header\">\n    <h1>\ud83d\udce1 Brand Social Listening Digest</h1>\n    <p>Brand: ${mention.brandName} &nbsp;|&nbsp; Report Date: ${mention.reportDate} &nbsp;|&nbsp; Platforms: Twitter/X, Reddit, News</p>\n    <div class=\"badge\">${sentimentIcon} Latest: ${mention.sentiment?.toUpperCase()}</div>\n  </div>\n\n  <div class=\"cards\">\n    <div class=\"card\"><div class=\"value\">${stats.total}</div><div class=\"label\">Total Mentions</div></div>\n    <div class=\"card\"><div class=\"value\" style=\"color:#22c55e\">${positiveRate}%</div><div class=\"label\">Positive Sentiment</div></div>\n    <div class=\"card\"><div class=\"value\" style=\"color:#ef4444\">${negativeRate}%</div><div class=\"label\">Negative Sentiment</div></div>\n    <div class=\"card\"><div class=\"value\" style=\"color:#f59e0b\">${stats.critical}</div><div class=\"label\">Critical Alerts</div></div>\n  </div>\n\n  <div class=\"section\">\n    <h2>\ud83d\udcca Sentiment Breakdown</h2>\n    <table><thead><tr><th>Sentiment</th><th>Count</th><th>Rate</th></tr></thead><tbody>\n      <tr><td>\u2705 Positive</td><td style=\"color:#22c55e;font-weight:bold\">${stats.positive}</td><td>${positiveRate}%</td></tr>\n      <tr><td>\u274c Negative</td><td style=\"color:#ef4444;font-weight:bold\">${stats.negative}</td><td>${negativeRate}%</td></tr>\n      <tr><td>\ud83d\ude10 Neutral</td><td style=\"color:#94a3b8\">${stats.neutral}</td><td>${neutralRate}%</td></tr>\n    </tbody></table>\n  </div>\n\n  <div class=\"section\">\n    <h2>\ud83c\udf10 Mentions by Platform</h2>\n    <table><thead><tr><th>Platform</th><th>Mentions</th></tr></thead><tbody>${platformRows}</tbody></table>\n  </div>\n\n  <div class=\"section\">\n    <h2>\ud83d\udd14 Latest Mention</h2>\n    <div class=\"mention-card\">\n      <strong>${mention.platform}</strong> \u2014 <span style=\"color:${sentimentColor}\">${mention.sentiment?.toUpperCase()}</span> &nbsp;|&nbsp; Urgency: <span style=\"color:${urgencyColor}\">${mention.urgency?.toUpperCase()}</span><br>\n      <p style=\"margin:8px 0;font-size:13px\">${mention.aiSummary || mention.text?.slice(0, 200)}</p>\n      <small>Topics: ${(mention.topics || []).join(', ') || 'N/A'} &nbsp;|&nbsp; Author: ${mention.author} &nbsp;|&nbsp; <a href=\"${mention.url}\">View Original</a></small>\n    </div>\n  </div>\n\n  <div class=\"footer\">Automated report generated by AI Social Listening Agent &nbsp;|&nbsp; ${mention.processedAt}</div>\n</body>\n</html>`;\n\nconst notificationMessage = `${sentimentIcon} *BRAND MENTION \u2014 ${mention.platform}*\\n\\n` +\n  `*Brand:* ${mention.brandName}\\n` +\n  `*Sentiment:* ${mention.sentiment?.toUpperCase()} (${mention.sentimentScore > 0 ? '+' : ''}${mention.sentimentScore?.toFixed(2)})\\n` +\n  `*Urgency:* ${mention.urgency?.toUpperCase()}\\n` +\n  `*Summary:* ${mention.aiSummary}\\n` +\n  `*Topics:* ${(mention.topics || []).join(', ') || 'N/A'}\\n` +\n  `*Author:* ${mention.author}\\n` +\n  `*Platform:* ${mention.platform}\\n` +\n  `*URL:* ${mention.url}\\n\\n` +\n  `*Session Stats:* ${stats.total} mentions | ${positiveRate}% positive | ${negativeRate}% negative`;\n\nreturn {\n  json: {\n    ...mention,\n    reportHtml,\n    notificationMessage,\n    notificationTitle: `${sentimentIcon} [${mention.platform}] ${mention.sentiment?.toUpperCase()} brand mention \u2014 ${mention.urgency?.toUpperCase()} urgency`,\n    shouldAlert: mention.requiresAlert || mention.urgency === 'critical',\n    sessionStats: stats\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "f146210a-6a32-406e-8798-8a779df66147",
      "name": "Filter mentions requiring alerts",
      "type": "n8n-nodes-base.filter",
      "position": [
        736,
        -240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "alert-filter",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $json.shouldAlert }}"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "72fb1a15-ce54-48cb-bd79-7e78689bc5dc",
      "name": "Post mention alert to Slack",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        960,
        -256
      ],
      "parameters": {
        "url": "YOUR_SLACK_WEBHOOK_URL",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"text\": \"{{ $json.notificationTitle }}\",\n  \"blocks\": [\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"{{ $json.notificationMessage }}\"\n      }\n    }\n  ]\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "64a6aa14-c229-45c8-b818-f245f8868bbd",
      "name": "Email HTML digest to marketing team",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        960,
        -64
      ],
      "parameters": {
        "html": "={{ $json.reportHtml }}",
        "options": {},
        "subject": "={{ $json.notificationTitle }}",
        "toEmail": "user@example.com",
        "fromEmail": "user@example.com"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "3eda856c-07fe-4eb2-8876-b8d8433c24be",
      "name": "Log success and update listening statistics",
      "type": "n8n-nodes-base.code",
      "position": [
        1184,
        -240
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Log successful mention processing and track statistics\nconst timestamp = new Date().toISOString();\nconst mention = $input.item.json;\n\nconsole.log(`\u2705 SUCCESS: Mention ${mention.mentionId} | Platform: ${mention.platform} | Sentiment: ${mention.sentiment} | Urgency: ${mention.urgency} | Duplicate: ${mention.isDuplicate} | Time: ${timestamp}`);\n\nconst stats = $getWorkflowStaticData('global').mentionStats || {};\n\nreturn {\n  json: {\n    success: true,\n    mentionId: mention.mentionId,\n    platform: mention.platform,\n    sentiment: mention.sentiment,\n    urgency: mention.urgency,\n    requiresResponse: mention.requiresResponse,\n    isDuplicate: mention.isDuplicate,\n    alertSent: mention.shouldAlert,\n    timestamp,\n    sessionStats: {\n      totalMentions: stats.total || 0,\n      positiveCount: stats.positive || 0,\n      negativeCount: stats.negative || 0,\n      neutralCount: stats.neutral || 0,\n      criticalAlerts: stats.critical || 0,\n      byPlatform: stats.byPlatform || {}\n    }\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "a9cc90cf-9c9c-481a-afc2-67af5d0de035",
      "name": "Wait For Result",
      "type": "n8n-nodes-base.wait",
      "position": [
        -384,
        -160
      ],
      "parameters": {},
      "typeVersion": 1.1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "7a1be7c0-e86e-4a4c-9003-f703640dd3bf",
  "connections": {
    "Wait For Result": {
      "main": [
        [
          {
            "node": "Process AI analysis results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Reddit mentions": {
      "main": [
        [
          {
            "node": "Merge all platform mentions",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Log mention to Airtable": {
      "main": [
        [
          {
            "node": "Generate HTML daily digest report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Twitter/X mentions": {
      "main": [
        [
          {
            "node": "Merge all platform mentions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch news article mentions": {
      "main": [
        [
          {
            "node": "Merge all platform mentions",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge all platform mentions": {
      "main": [
        [
          {
            "node": "Normalize mentions into unified schema",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post mention alert to Slack": {
      "main": [
        [
          {
            "node": "Log success and update listening statistics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process AI analysis results": {
      "main": [
        [
          {
            "node": "Route by sentiment and urgency",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send critical mention alert": {
      "main": [
        [
          {
            "node": "Generate HTML daily digest report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set brand monitoring config": {
      "main": [
        [
          {
            "node": "Fetch Twitter/X mentions",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Reddit mentions",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch news article mentions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by sentiment and urgency": {
      "main": [
        [
          {
            "node": "Send critical mention alert",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log mention to Airtable",
            "type": "main",
            "index": 0
          },
          {
            "node": "Generate HTML daily digest report",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log mention to Airtable",
            "type": "main",
            "index": 0
          },
          {
            "node": "Generate HTML daily digest report",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log mention to Airtable",
            "type": "main",
            "index": 0
          },
          {
            "node": "Generate HTML daily digest report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter mentions requiring alerts": {
      "main": [
        [
          {
            "node": "Post mention alert to Slack",
            "type": "main",
            "index": 0
          },
          {
            "node": "Email HTML digest to marketing team",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI sentiment and urgency analysis": {
      "main": [
        [
          {
            "node": "Wait For Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate HTML daily digest report": {
      "main": [
        [
          {
            "node": "Filter mentions requiring alerts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Monitor brand mentions every hour": {
      "main": [
        [
          {
            "node": "Set brand monitoring config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email HTML digest to marketing team": {
      "main": [
        [
          {
            "node": "Log success and update listening statistics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize mentions into unified schema": {
      "main": [
        [
          {
            "node": "AI sentiment and urgency analysis",
            "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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Monitors brand mentions across Twitter/X, Reddit, and News APIs in real-time (or scheduled), fetches mentions in parallel, normalizes data, uses AI to analyze sentiment/urgency/topics, detects duplicates, filters critical mentions, logs everything to Airtable, posts alerts to…

Source: https://n8n.io/workflows/13653/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Tech Daily Digest. Uses rssFeedRead, emailSend, httpRequest. Scheduled trigger; 22 nodes.

RSS Feed Read, Email Send, HTTP Request
AI & RAG

Daily AI Research Agent. Uses httpRequest, telegram, emailSend. Scheduled trigger; 11 nodes.

HTTP Request, Telegram, Email Send
AI & RAG

Agent Studio - Weekly Analytics Report. Uses httpRequest, emailSend. Scheduled trigger; 8 nodes.

HTTP Request, Email Send
AI & RAG

E-Décor - AI Agent Assistant. Uses httpRequest, emailSend. Scheduled trigger; 6 nodes.

HTTP Request, Email Send
AI & RAG

Online Marketing Weekly Report. Uses scheduleTrigger, lmChatOpenAi, toolWorkflow, executeWorkflowTrigger. Scheduled trigger; 51 nodes.

OpenAI Chat, Tool Workflow, Execute Workflow Trigger +8