AutomationFlowsSocial Media › Send Weekly Brand and Competitor Intel Digests to Slack with Claude Web Search

Send Weekly Brand and Competitor Intel Digests to Slack with Claude Web Search

ByAnas Ashfaq @anas-elandz on n8n.io

This workflow runs weekly to search the web (including Reddit) for your brand, competitors, and industry keywords using Anthropic Claude web search, then synthesizes the most relevant findings into a ranked digest and posts a grouped summary to a chosen Slack channel. Runs every…

Cron / scheduled trigger★★★★☆ complexity19 nodesHTTP RequestSlack
Social Media Trigger: Cron / scheduled Nodes: 19 Complexity: ★★★★☆ Added:

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

This workflow follows the HTTP Request → Slack 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": "uPGsnzY4r1UoeUDq",
  "name": "Monitor brand and competitor mentions on Reddit and web, post weekly digest to Slack",
  "tags": [],
  "nodes": [
    {
      "id": "bf842e51-4300-49ac-b5d7-823bd9c5d9c1",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1088,
        1088
      ],
      "parameters": {
        "width": 480,
        "height": 720,
        "content": "## Monitor brand and competitor mentions on Reddit and web, post weekly digest to Slack\n\n### How it works\n\nThis workflow runs weekly to monitor brand, competitor, and topic mentions across Reddit and the wider web. It prepares keyword searches, uses Claude via the Anthropic API to find and synthesize relevant mentions, then formats the resulting digest and posts it to Slack.\n\n### Setup steps\n\n- Configure the Weekly Schedule node with the desired run day and time.\n- Update the Monitoring Config node with the brand name, competitor list, tracked topics, and Slack channel.\n- Add Anthropic API credentials or headers for the Claude HTTP Request nodes.\n- Connect Slack credentials and ensure the bot has permission to post in the target channel.\n\n### Customization\n\nAdjust the keyword-splitting logic, Claude prompts, monitored competitors/topics, or Slack formatting to change the scope and style of the weekly digest."
      },
      "typeVersion": 1
    },
    {
      "id": "007c9875-d82e-40ed-a336-8c11ae7bab76",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1648,
        1088
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 336,
        "content": "## Schedule and configure\n\nStarts the workflow on a weekly cadence and defines the monitoring inputs, including brand name, competitors, topics, and target Slack channel."
      },
      "typeVersion": 1
    },
    {
      "id": "57d78e5d-31e5-496b-ac51-ba5065ac33f5",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2080,
        1104
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 320,
        "content": "## Prepare web searches\n\nSplits the monitoring configuration into keyword-based search items and builds the Claude web search request payloads."
      },
      "typeVersion": 1
    },
    {
      "id": "662a854d-e4e2-4689-92e4-0681c692a5d6",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2512,
        1088
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 336,
        "content": "## Search and parse mentions\n\nCalls Anthropic Claude to search the web for relevant brand, competitor, and topic mentions, then parses the returned results into structured data."
      },
      "typeVersion": 1
    },
    {
      "id": "0f3822c8-3be9-4d41-bd29-9334894d1119",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2944,
        1104
      ],
      "parameters": {
        "color": 7,
        "width": 384,
        "height": 320,
        "content": "## Collect digest inputs\n\nAggregates all parsed mention results and prepares the prompt that will be used to generate the weekly summary digest."
      },
      "typeVersion": 1
    },
    {
      "id": "18631361-0df2-48c2-87a7-a160a3716667",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3360,
        1104
      ],
      "parameters": {
        "color": 7,
        "width": 384,
        "height": 320,
        "content": "## Generate AI digest\n\nSends the collected results to Claude for synthesis and parses the generated digest response for downstream formatting."
      },
      "typeVersion": 1
    },
    {
      "id": "f53249d2-1a2a-4213-95f4-7a3a929a7695",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3776,
        1104
      ],
      "parameters": {
        "color": 7,
        "width": 384,
        "height": 320,
        "content": "## Post Slack summary\n\nFormats the digest into a Slack-friendly message and posts the final weekly update to the configured channel."
      },
      "typeVersion": 1
    },
    {
      "id": "e2493236-85c1-47cf-b37e-9499a7ac9f35",
      "name": "Weekly Trigger at Monday 8am",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        1696,
        1264
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 8
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "f540d514-9f3c-48c4-8994-d2fb818f1d85",
      "name": "Set Monitoring Parameters",
      "type": "n8n-nodes-base.set",
      "position": [
        1904,
        1264
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg-001",
              "name": "brand_name",
              "type": "string",
              "value": "YourBrand Name"
            },
            {
              "id": "cfg-002",
              "name": "competitors",
              "type": "string",
              "value": "competitor1, competitor2"
            },
            {
              "id": "cfg-003",
              "name": "topics",
              "type": "string",
              "value": "industry keyword 1, industry keyword 2"
            },
            {
              "id": "cfg-004",
              "name": "slack_channel",
              "type": "string",
              "value": "Your Slack Channel ID"
            },
            {
              "id": "cfg-005",
              "name": "lookback_days",
              "type": "number",
              "value": 7
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "4c9c4c81-7a14-4189-8b65-18f6264cbdbd",
      "name": "Extract Keywords from Config",
      "type": "n8n-nodes-base.code",
      "position": [
        2128,
        1264
      ],
      "parameters": {
        "jsCode": "const config = $input.all()[0].json;\nconst brand = config.brand_name || '';\nconst competitors = config.competitors ? config.competitors.split(',').map(s => s.trim()).filter(s => s) : [];\nconst topics = config.topics ? config.topics.split(',').map(s => s.trim()).filter(s => s) : [];\nconst keywords = [brand, ...competitors, ...topics].filter(k => k);\n\nconst brandLower = brand.toLowerCase();\nconst competitorsLower = competitors.map(c => c.toLowerCase());\n\nreturn keywords.map(keyword => {\n  const kl = keyword.toLowerCase();\n  const keyword_type = kl === brandLower ? 'brand_mention'\n    : competitorsLower.includes(kl) ? 'competitor_news'\n    : 'industry_signal';\n  return {\n    json: {\n      keyword,\n      keyword_type,\n      slack_channel: config.slack_channel,\n      lookback_days: config.lookback_days || 7\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "92d31278-e9ae-4bbe-b1d4-17c38aad2dfb",
      "name": "Generate Claude Search Requests",
      "type": "n8n-nodes-base.code",
      "position": [
        2336,
        1264
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const keyword = $input.item.json.keyword;\nconst keyword_type = $input.item.json.keyword_type;\nconst slack_channel = $input.item.json.slack_channel;\nconst lookback_days = $input.item.json.lookback_days;\n\nconst requestBody = {\n  model: 'claude-opus-4-5',\n  max_tokens: 1500,\n  temperature: 0,\n  tools: [{ type: 'web_search_20250305', name: 'web_search', max_uses: 5 }],\n  messages: [{\n    role: 'user',\n    content: `Search the web for concrete recent mentions of \"${keyword}\" from the past ${lookback_days} days.\\n\\nInclude: news articles, blog posts, Reddit discussions, product launches, funding news, community discussions.\\n\\nReturn ONLY a JSON array (no markdown, no explanation). Each item must have a real URL you found. Max 4 items. Return [] if nothing concrete found.\\n\\n[{\"headline\":\"specific title max 10 words\",\"url\":\"https://actual-url-you-found\",\"source\":\"Publication name or Reddit r/subreddit\",\"type\":\"brand_mention or competitor_news or industry_signal\",\"why_it_matters\":\"max 10 words punchy\"}]`\n  }]\n};\nreturn { json: { keyword, keyword_type, slack_channel, lookback_days, requestBody } };"
      },
      "typeVersion": 2
    },
    {
      "id": "6f3a9a63-1d23-44ad-90ad-481e8cca5d3f",
      "name": "Post to Claude API",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2560,
        1264
      ],
      "parameters": {
        "url": "https://api.anthropic.com/v1/messages",
        "method": "POST",
        "options": {
          "timeout": 120000,
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "jsonBody": "={{ $json.requestBody }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            },
            {
              "name": "anthropic-beta",
              "value": "web-search-2025-03-05"
            }
          ]
        },
        "nodeCredentialType": "anthropicApi"
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "5489365d-2e24-4032-a8d9-543e58b66603",
      "name": "Parse Claude API Responses",
      "type": "n8n-nodes-base.code",
      "position": [
        2768,
        1264
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const prev = $('Generate Claude Search Requests').item.json;\nconst keyword = prev.keyword;\nconst keyword_type = prev.keyword_type;\nconst slack_channel = prev.slack_channel;\n\nconst blocks = ($input.item.json.content || []).filter(b => b.type === 'text');\nconst text = blocks.length > 0 ? blocks[blocks.length - 1].text : '[]';\n\nlet web_findings = [];\ntry {\n  const match = text.match(/\\[[\\s\\S]*\\]/);\n  if (match) {\n    const parsed = JSON.parse(match[0]);\n    web_findings = parsed\n      .filter(f => f.url && f.url.startsWith('http') && f.headline)\n      .map(f => ({ ...f, type: keyword_type }));\n  }\n} catch(e) {\n  web_findings = [];\n}\n\nreturn { json: { keyword, slack_channel, all_findings: web_findings } };"
      },
      "typeVersion": 2
    },
    {
      "id": "56f8dd95-c591-4e8f-b82f-c901eae5cd3d",
      "name": "Aggregate Search Results",
      "type": "n8n-nodes-base.code",
      "position": [
        2992,
        1264
      ],
      "parameters": {
        "jsCode": "const allItems = $input.all();\nconst slack_channel = allItems[0].json.slack_channel;\n\nconst seen = new Set();\nconst all_findings = [];\nfor (const item of allItems) {\n  for (const f of (item.json.all_findings || [])) {\n    const key = (f.url || f.headline || '').toLowerCase();\n    if (!seen.has(key) && key) {\n      seen.add(key);\n      all_findings.push(f);\n    }\n  }\n}\n\nreturn [{ json: { slack_channel, all_findings } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "2635533d-b640-454e-a81d-f596fed62513",
      "name": "Create Digest Content",
      "type": "n8n-nodes-base.code",
      "position": [
        3184,
        1264
      ],
      "parameters": {
        "jsCode": "const all_findings = $input.all()[0].json.all_findings || [];\nconst slack_channel = $input.all()[0].json.slack_channel;\n\nif (all_findings.length === 0) {\n  const requestBody = {\n    model: 'claude-opus-4-5',\n    max_tokens: 50,\n    temperature: 0,\n    messages: [{ role: 'user', content: 'Return exactly: []' }]\n  };\n  return [{ json: { slack_channel, requestBody } }];\n}\n\nconst findingsJson = JSON.stringify(all_findings, null, 2);\n\nconst prompt = `You are a competitive intelligence analyst. Below are pre-researched findings with real URLs, gathered from web searches this week.\n\nFINDINGS TO RANK:\n${findingsJson}\n\nTASK: Review, deduplicate, and return the top 8 most business-relevant findings.\n- Keep the original URLs exactly as provided\n- You may improve the headline (max 12 words) and why_it_matters (max 10 words, punchy)\n- Keep the type (brand_mention / competitor_news / industry_signal) \u2014 these are already correctly classified, do not change them\n- Order by business relevance\n\nReturn ONLY a valid JSON array, no markdown:\n[{\"type\":\"...\",\"source\":\"...\",\"headline\":\"...\",\"why_it_matters\":\"...\",\"url\":\"...\"}]`;\n\nconst requestBody = {\n  model: 'claude-opus-4-5',\n  max_tokens: 2048,\n  temperature: 0,\n  messages: [{ role: 'user', content: prompt }]\n};\nreturn [{ json: { slack_channel, requestBody } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "5a89a616-e1e3-41aa-8d64-d3a73547cdf6",
      "name": "Post to Claude for Synthesis",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3408,
        1264
      ],
      "parameters": {
        "url": "https://api.anthropic.com/v1/messages",
        "method": "POST",
        "options": {
          "timeout": 60000,
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "jsonBody": "={{ $json.requestBody }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            }
          ]
        },
        "nodeCredentialType": "anthropicApi"
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "4af284ca-748e-4a56-9481-a0fa053f4f15",
      "name": "Interpret Digest Results",
      "type": "n8n-nodes-base.code",
      "position": [
        3600,
        1264
      ],
      "parameters": {
        "jsCode": "const slack_channel = $('Create Digest Content').first().json.slack_channel;\nconst blocks = ($input.all()[0].json.content || []).filter(b => b.type === 'text');\nconst text = blocks.length > 0 ? blocks[blocks.length - 1].text : '[]';\nlet findings = [];\ntry {\n  const match = text.match(/\\[\\s*\\{[\\s\\S]*\\}\\s*\\]/);\n  if (match) findings = JSON.parse(match[0]);\n} catch (e) {\n  findings = [];\n}\nreturn [{ json: { slack_channel, findings } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "ede7a04a-ddd1-4ddd-9050-c57414cf3067",
      "name": "Prepare Slack Message Format",
      "type": "n8n-nodes-base.code",
      "position": [
        3824,
        1264
      ],
      "parameters": {
        "jsCode": "const findings = $input.all()[0].json.findings || [];\nconst slack_channel = $input.all()[0].json.slack_channel;\nconst cfg = $('Set Monitoring Parameters').first().json;\nconst today = new Date().toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' });\n\nconst trim = (str, maxWords) => {\n  if (!str) return '';\n  const words = str.trim().split(/\\s+/);\n  return words.length <= maxWords ? str.trim() : words.slice(0, maxWords).join(' ') + '...';\n};\n\nconst brandMentions   = findings.filter(f => f.type === 'brand_mention');\nconst competitorNews  = findings.filter(f => f.type === 'competitor_news');\nconst industrySignals = findings.filter(f => f.type === 'industry_signal');\n\nconst fmt = items => items.map(f => {\n  let headline;\n  if (f.url && f.url.startsWith('http')) {\n    headline = '<' + f.url + '|' + f.headline.trim() + '>';\n  } else {\n    headline = f.headline.trim();\n  }\n  const why = trim(f.why_it_matters, 12);\n  let line = '\\u2022 ' + headline + '\\n   _' + (f.source || 'Web') + '_ \\u00b7 ' + why;\n  if (f.url && !f.url.startsWith('http')) {\n    line += '\\n   ' + f.url;\n  }\n  return line;\n}).join('\\n');\n\nlet text = ':bar_chart: *Weekly Intel* \\u2014 ' + today;\n\nif (findings.length === 0) {\n  text += '\\n_No verified mentions found this week. Check back next Monday._';\n} else {\n  if (brandMentions.length   > 0) text += '\\n\\n:label: *Brand (' + brandMentions.length + ')*\\n'   + fmt(brandMentions);\n  if (competitorNews.length  > 0) text += '\\n\\n:crossed_swords: *Competitors (' + competitorNews.length + ')*\\n' + fmt(competitorNews);\n  if (industrySignals.length > 0) text += '\\n\\n:satellite: *Industry (' + industrySignals.length + ')*\\n'  + fmt(industrySignals);\n}\n\nconst parts = [cfg.brand_name, cfg.competitors, cfg.topics].filter(v => v && v.trim() !== 'YourBrand' && v.trim() !== '');\nif (parts.length) text += '\\n\\n_Tracking: ' + parts.join(' \\u00b7 ') + '_';\n\nreturn [{ json: { slack_channel, message_text: text } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "40e822d3-bc9c-43e1-b076-45d0477bae9d",
      "name": "Send Digest to Slack Channel",
      "type": "n8n-nodes-base.slack",
      "position": [
        4016,
        1264
      ],
      "parameters": {
        "text": "={{ $json.message_text }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.slack_channel }}"
        },
        "otherOptions": {
          "mrkdwn": true,
          "includeLinkToWorkflow": false
        }
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false,
    "executionOrder": "v1",
    "saveManualExecutions": true
  },
  "versionId": "2a49c757-6506-49e2-ba2a-1694b10b3e94",
  "connections": {
    "Post to Claude API": {
      "main": [
        [
          {
            "node": "Parse Claude API Responses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Digest Content": {
      "main": [
        [
          {
            "node": "Post to Claude for Synthesis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate Search Results": {
      "main": [
        [
          {
            "node": "Create Digest Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Interpret Digest Results": {
      "main": [
        [
          {
            "node": "Prepare Slack Message Format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Monitoring Parameters": {
      "main": [
        [
          {
            "node": "Extract Keywords from Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Claude API Responses": {
      "main": [
        [
          {
            "node": "Aggregate Search Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Keywords from Config": {
      "main": [
        [
          {
            "node": "Generate Claude Search Requests",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post to Claude for Synthesis": {
      "main": [
        [
          {
            "node": "Interpret Digest Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Slack Message Format": {
      "main": [
        [
          {
            "node": "Send Digest to Slack Channel",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Weekly Trigger at Monday 8am": {
      "main": [
        [
          {
            "node": "Set Monitoring Parameters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Claude Search Requests": {
      "main": [
        [
          {
            "node": "Post to Claude API",
            "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

This workflow runs weekly to search the web (including Reddit) for your brand, competitors, and industry keywords using Anthropic Claude web search, then synthesizes the most relevant findings into a ranked digest and posts a grouped summary to a chosen Slack channel. Runs every…

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

More Social Media workflows → · Browse all categories →

Related workflows

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

Social Media

This enterprise-grade n8n workflow automates the Instagram complaint handling process — from detection to resolution — using Claude AI, dynamic ticket assignment, and SLA enforcement. It converts cust

HTTP Request, Google Sheets, Slack
Social Media

This enterprise-grade n8n workflow automates influencer contract compliance for Instagram campaigns — from deadline tracking to breach detection — using Claude AI, Instagram API, and smart reminders.

Google Sheets, Slack, HTTP Request
Social Media

Convert your customer satisfaction into high-converting social media content with this fully automated social proof pipeline. This workflow scans your database for top-tier reviews, generates a brande

N8N Nodes Uploadtourl, Airtable, HTTP Request +1
Social Media

Youtube Videos Checker. Uses httpRequest, googleSheets, slack. Scheduled trigger; 18 nodes.

HTTP Request, Google Sheets, Slack
Social Media

Turn your best 5-star reviews into a daily stream of branded social proof content -- fully automated. This workflow pulls the oldest unposted 5-star review from Google Sheets, generates a custom quote

Google Sheets, HTTP Request, N8N Nodes Uploadtourl +1