โ† All skills
Tencent SkillHub ยท Communication & Collaboration

Social Listening & Brand Reputation Monitor

Monitor Twitter, Reddit, forums, and news for brand mentions; analyze sentiment, detect reputation crises, and send instant alerts to Slack, Telegram, or email.

skill openclawclawhub Free
0 Downloads
0 Stars
0 Installs
0 Score
High Signal

Monitor Twitter, Reddit, forums, and news for brand mentions; analyze sentiment, detect reputation crises, and send instant alerts to Slack, Telegram, or email.

โฌ‡ 0 downloads โ˜… 0 stars Unverified but indexed

Install for OpenClaw

Known item issue.

This item's current download entry is known to bounce back to a listing or homepage instead of returning a package file.

Quick setup
  1. Open the source page and confirm the package flow manually.
  2. Review SKILL.md if you can obtain the files.
  3. Treat this source as manual setup until the download is verified.

Requirements

Target platform
OpenClaw
Install method
Manual import
Extraction
Extract archive
Prerequisites
OpenClaw
Primary doc
SKILL.md

Package facts

Download mode
Manual review
Package format
ZIP package
Source platform
Tencent SkillHub
What's included
SKILL.md

Validation

  • Open the source listing and confirm there is a real package or setup artifact available.
  • Review SKILL.md before asking your agent to continue.
  • Treat this source as manual setup until the upstream download flow is fixed.

Install with your agent

Agent handoff

Use the source page and any available docs to guide the install because the item currently does not return a direct package file.

  1. Open the source page via Open source listing.
  2. If you can obtain the package, extract it into a folder your agent can access.
  3. Paste one of the prompts below and point your agent at the source page and extracted files.
New install

I tried to install a skill package from Yavira, but the item currently does not return a direct package file. Inspect the source page and any extracted docs, then tell me what you can confirm and any manual steps still required.

Upgrade existing

I tried to upgrade a skill package from Yavira, but the item currently does not return a direct package file. Compare the source page and any extracted docs with my current installation, then summarize what changed and what manual follow-up I still need.

Trust & source

Release facts

Source
Tencent SkillHub
Verification
Indexed source record
Version
1.0.0

Documentation

ClawHub primary doc Primary doc: SKILL.md 25 sections Open source page

Overview

This skill builds a real-time brand reputation monitoring system that: Apify scrapes Twitter/X, Reddit, forums, and news sites for every mention of your brand Claude (OpenClaw) analyzes sentiment, detects crises, and classifies each mention Alerts fire instantly to Slack, Telegram, or email when reputation risk is detected The result: you know what people are saying about your brand the moment they say it โ€” and you can respond before it becomes a crisis. ๐Ÿ”— Apify: https://www.apify.com/?fpr=dx06p

What This Skill Does

Monitor Twitter/X, Reddit, forums, and news for brand mentions in real-time Perform sentiment analysis on every mention (positive / negative / neutral) Detect crisis signals โ€” sudden spikes in negative mentions Track competitor mentions for comparative reputation benchmarking Score reputation health over time with a rolling dashboard score Alert immediately on Slack/Telegram when a crisis threshold is crossed Generate weekly reputation reports with trends and actionable insights Distinguish genuine complaints from spam or bot activity

Architecture Overview

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ SOCIAL LISTENING & REPUTATION MONITOR โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ LAYER 1 โ€” MENTION SCRAPING (Apify) โ”‚ โ”‚ โ”‚ โ”‚ Twitter/X โ”‚ Reddit โ”‚ Hacker News โ”‚ Google News โ”‚ โ”‚ โ”‚ โ”‚ Trustpilot โ”‚ G2 โ”‚ App Store โ”‚ Niche Forums โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ LAYER 2 โ€” REPUTATION ANALYSIS ENGINE (Claude) โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ€ข Sentiment Classifier โ†’ pos / neg / neutral + score โ”‚ โ”‚ โ”‚ โ”‚ โ€ข Crisis Detector โ†’ spike in neg mentions โ”‚ โ”‚ โ”‚ โ”‚ โ€ข Topic Categorizer โ†’ product | support | pr | etc โ”‚ โ”‚ โ”‚ โ”‚ โ€ข Influence Scorer โ†’ who is talking (reach) โ”‚ โ”‚ โ”‚ โ”‚ โ€ข Response Generator โ†’ suggested reply drafts โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ LAYER 3 โ€” ALERTS & REPORTING โ”‚ โ”‚ โ”‚ โ”‚ Slack โ”‚ Telegram โ”‚ Email โ”‚ Dashboard โ”‚ Weekly Report โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Apify

Sign up at https://www.apify.com/?fpr=dx06p Go to Settings โ†’ Integrations Copy your token: export APIFY_TOKEN=apify_api_xxxxxxxxxxxxxxxx

Claude / OpenClaw

export CLAUDE_API_KEY=sk-ant-xxxxxxxxxxxxxxxx

Slack Webhook (optional)

Go to api.slack.com/apps โ†’ Create App โ†’ Incoming Webhooks Copy the webhook URL: export SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxx/xxx/xxx

Telegram Bot (optional)

export TELEGRAM_BOT_TOKEN=123456789:AABBccDDeeFFggHH export TELEGRAM_CHAT_ID=-1001234567890

Step 2 โ€” Install Dependencies

npm install apify-client axios node-cron dotenv

Configuration โ€” Define Your Brand

// config.js export const BRAND_CONFIG = { brandName: "YourBrand", keywords: [ "YourBrand", "YourBrand.com", "@YourBrandHandle", "#YourBrand", "your brand common misspelling" ], competitors: ["CompetitorA", "CompetitorB"], crisisThreshold: { negativeSpike: 5, // alert if 5+ negative mentions in one scan sentimentDrop: 20, // alert if sentiment score drops 20 points viralThreshold: 1000 // alert if a negative post hits 1000+ engagements }, language: "en", timezone: "America/New_York" };

Scrape Twitter/X Mentions

import ApifyClient from 'apify-client'; import { BRAND_CONFIG } from './config.js'; const apify = new ApifyClient({ token: process.env.APIFY_TOKEN }); async function scrapeTwitterMentions() { console.log("๐Ÿฆ Scraping Twitter/X mentions..."); const run = await apify.actor("apify/twitter-scraper").call({ searchTerms: BRAND_CONFIG.keywords, maxTweets: 100, addUserInfo: true, startUrls: [], languageFilter: BRAND_CONFIG.language }); const { items } = await run.dataset().getData(); return items.map(t => ({ source: "twitter", id: t.id, text: t.fullText || t.text, author: t.author?.userName, authorName: t.author?.name, followers: t.author?.followers || 0, verified: t.author?.isVerified || false, likes: t.likeCount || 0, retweets: t.retweetCount || 0, replies: t.replyCount || 0, engagements: (t.likeCount || 0) + (t.retweetCount || 0) * 2 + (t.replyCount || 0), url: t.url, createdAt: t.createdAt, scrapedAt: new Date().toISOString() })); }

Scrape Reddit Mentions

async function scrapeRedditMentions() { console.log("๐Ÿ‘ฝ Scraping Reddit mentions..."); const searchQueries = BRAND_CONFIG.keywords.map(k => apify.actor("apify/reddit-search-scraper").call({ queries: [k], maxItems: 30, sort: "new" }).then(run => run.dataset().getData()) .then(d => d.items) ); const results = await Promise.all(searchQueries); return results.flat().map(p => ({ source: "reddit", id: p.id, text: p.title + " " + (p.selftext || ""), title: p.title, author: p.author, subreddit: p.subreddit, score: p.score, comments: p.numComments, upvoteRatio: p.upvoteRatio, engagements: p.score + p.numComments * 2, url: p.url, createdAt: new Date(p.created * 1000).toISOString(), scrapedAt: new Date().toISOString() })); }

Scrape News & Review Platforms

async function scrapeNewsAndReviews() { console.log("๐Ÿ“ฐ Scraping news and reviews..."); const brandQuery = BRAND_CONFIG.brandName; const [news, trustpilot, hackerNews] = await Promise.all([ // Google News apify.actor("apify/google-search-scraper").call({ queries: [`"${brandQuery}" news`], maxPagesPerQuery: 2, resultsPerPage: 20, dateRange: "pastWeek" }).then(run => run.dataset().getData()) .then(d => d.items.map(r => ({ source: "google_news", text: r.title + " " + r.snippet, title: r.title, url: r.url, createdAt: r.date || new Date().toISOString(), scrapedAt: new Date().toISOString() }))), // Trustpilot reviews apify.actor("apify/trustpilot-scraper").call({ startUrls: [{ url: `https://www.trustpilot.com/review/${brandQuery.toLowerCase()}.com` }], maxReviews: 50, filterScore: [1, 2, 3] // focus on negative/neutral }).then(run => run.dataset().getData()) .then(d => d.items.map(r => ({ source: "trustpilot", text: r.reviewBody, title: r.reviewTitle, rating: r.ratingValue, author: r.author, url: r.url, createdAt: r.datePublished, scrapedAt: new Date().toISOString() }))).catch(() => []), // graceful fail if brand not on Trustpilot // Hacker News apify.actor("apify/hacker-news-scraper").call({ searchQuery: brandQuery, maxItems: 20, type: "story" }).then(run => run.dataset().getData()) .then(d => d.items.map(r => ({ source: "hacker_news", text: r.title + " " + (r.text || ""), title: r.title, author: r.by, score: r.score, comments: r.descendants, url: r.url || `https://news.ycombinator.com/item?id=${r.id}`, createdAt: new Date(r.time * 1000).toISOString(), scrapedAt: new Date().toISOString() }))).catch(() => []) ]); return [...news, ...trustpilot, ...hackerNews]; }

Aggregate All Mentions

async function scrapeAllMentions() { const [twitter, reddit, newsReviews] = await Promise.all([ scrapeTwitterMentions(), scrapeRedditMentions(), scrapeNewsAndReviews() ]); const all = [...twitter, ...reddit, ...newsReviews]; // Deduplicate by URL const seen = new Set(); return all.filter(m => { if (seen.has(m.url)) return false; seen.add(m.url); return true; }); }

Sentiment Classifier

import axios from 'axios'; const claude = axios.create({ baseURL: 'https://api.anthropic.com/v1', headers: { 'x-api-key': process.env.CLAUDE_API_KEY, 'anthropic-version': '2023-06-01', 'Content-Type': 'application/json' } }); async function analyzeSentiment(mentions) { const prompt = ` You are a brand reputation analyst. Analyze each mention and classify it. BRAND: ${BRAND_CONFIG.brandName} MENTIONS TO ANALYZE: ${JSON.stringify(mentions.slice(0, 30), null, 2)} Respond ONLY in this JSON format: { "analyzedMentions": [ { "id": "mention id or url", "sentiment": "positive | negative | neutral | mixed", "sentimentScore": 7, "confidenceLevel": "high | medium | low", "emotionalTone": "angry | frustrated | disappointed | happy | excited | neutral | sarcastic", "category": "product_feedback | customer_support | pr_crisis | competitor_comparison | spam | praise | question | bug_report", "urgency": "critical | high | medium | low", "isInfluencer": true, "requiresResponse": true, "suggestedResponseTone": "apologetic | informative | appreciative | ignore", "keyTopics": ["topic1", "topic2"], "isCrisisSignal": false, "summary": "one-line summary of what was said" } ], "batchSentiment": { "positive": 0, "negative": 0, "neutral": 0, "mixed": 0, "overallScore": 65, "trend": "improving | declining | stable" }, "crisisSignals": [ { "signal": "description of the risk", "severity": "critical | high | medium", "source": "platform", "url": "url of the post", "recommendedAction": "what to do right now" } ], "topComplaintsThisRound": ["complaint 1", "complaint 2"], "topPraisesThisRound": ["praise 1", "praise 2"] } `; const { data } = await claude.post('/messages', { model: "claude-opus-4-5", max_tokens: 4000, messages: [{ role: "user", content: prompt }] }); return JSON.parse(data.content[0].text.replace(/```json|```/g, '').trim()); }

Crisis Detector

// Rolling sentiment history (use Redis/DB in production) const sentimentHistory = []; function detectCrisis(analysis) { const crisisAlerts = []; const batch = analysis.batchSentiment; const signals = analysis.crisisSignals || []; // Track history sentimentHistory.push({ score: batch.overallScore, negative: batch.negative, timestamp: new Date().toISOString() }); const prev = sentimentHistory[sentimentHistory.length - 2]; // CRISIS TRIGGER 1 โ€” Spike in negative mentions if (batch.negative >= BRAND_CONFIG.crisisThreshold.negativeSpike) { crisisAlerts.push({ type: "negative_spike", severity: "critical", message: `๐Ÿšจ ${batch.negative} negative mentions detected in this scan`, threshold: BRAND_CONFIG.crisisThreshold.negativeSpike, current: batch.negative }); } // CRISIS TRIGGER 2 โ€” Sentiment score drop if (prev && (prev.score - batch.overallScore) >= BRAND_CONFIG.crisisThreshold.sentimentDrop) { crisisAlerts.push({ type: "sentiment_drop", severity: "high", message: `๐Ÿ“‰ Sentiment dropped from ${prev.score} to ${batch.overallScore} (-${prev.score - batch.overallScore} pts)`, previousScore: prev.score, currentScore: batch.overallScore }); } // CRISIS TRIGGER 3 โ€” High-engagement negative post const viralNegative = analysis.analyzedMentions?.filter(m => m.sentiment === "negative" && m.urgency === "critical" ) || []; if (viralNegative.length > 0) { crisisAlerts.push({ type: "viral_negative", severity: "high", message: `๐Ÿ”ฅ ${viralNegative.length} high-urgency negative mention(s) detected`, mentions: viralNegative.map(m => m.id) }); } // Add explicit crisis signals from Claude signals.forEach(signal => { if (signal.severity === "critical" || signal.severity === "high") { crisisAlerts.push({ ...signal, type: "claude_signal" }); } }); return crisisAlerts; }

Response Suggestion Generator

async function generateResponseSuggestions(urgentMentions) { if (urgentMentions.length === 0) return []; const prompt = ` You are a brand communications expert. Write response suggestions for these urgent mentions. Be empathetic, on-brand, and action-oriented. Never defensive. BRAND: ${BRAND_CONFIG.brandName} URGENT MENTIONS REQUIRING RESPONSE: ${JSON.stringify(urgentMentions.slice(0, 5), null, 2)} Respond ONLY in this JSON format: { "suggestions": [ { "mentionId": "id or url", "platform": "twitter | reddit | etc", "originalText": "what they said (summarized)", "sentiment": "negative | mixed", "responseOptions": [ { "tone": "apologetic", "response": "full suggested response text", "bestFor": "when the issue is your fault" }, { "tone": "informative", "response": "full suggested response text", "bestFor": "when it is a misunderstanding" } ], "doNotDo": "what to avoid saying in this specific case", "priority": "respond within 1h | 4h | 24h" } ] } `; const { data } = await claude.post('/messages', { model: "claude-opus-4-5", max_tokens: 2500, messages: [{ role: "user", content: prompt }] }); return JSON.parse(data.content[0].text.replace(/```json|```/g, '').trim()); }

Slack Alert Publisher

async function sendSlackAlert(crisisAlerts, analysis, responses) { const isCrisis = crisisAlerts.some(a => a.severity === "critical"); const color = isCrisis ? "#FF0000" : "#FFA500"; const icon = isCrisis ? "๐Ÿšจ" : "โš ๏ธ"; const payload = { attachments: [{ color, blocks: [ { type: "header", text: { type: "plain_text", text: `${icon} Brand Alert: ${BRAND_CONFIG.brandName}` } }, { type: "section", fields: [ { type: "mrkdwn", text: `*Sentiment Score:*\n${analysis.batchSentiment.overallScore}/100` }, { type: "mrkdwn", text: `*Trend:*\n${analysis.batchSentiment.trend}` }, { type: "mrkdwn", text: `*Negative Mentions:*\n${analysis.batchSentiment.negative}` }, { type: "mrkdwn", text: `*Requires Response:*\n${responses?.suggestions?.length || 0} mentions` } ] }, ...crisisAlerts.map(alert => ({ type: "section", text: { type: "mrkdwn", text: `*${alert.severity?.toUpperCase()}:* ${alert.message}\n${alert.recommendedAction || ""}` } })), { type: "section", text: { type: "mrkdwn", text: `*Top Complaints:*\n${analysis.topComplaintsThisRound?.map(c => `โ€ข ${c}`).join('\n') || "None"}` } } ] }] }; await axios.post(process.env.SLACK_WEBHOOK_URL, payload); }

Telegram Crisis Alert

async function sendTelegramAlert(crisisAlerts, analysis) { const severity = crisisAlerts[0]?.severity || "medium"; const icon = severity === "critical" ? "๐Ÿšจ๐Ÿšจ๐Ÿšจ" : "โš ๏ธ"; const message = ` ${icon} *BRAND ALERT: ${BRAND_CONFIG.brandName}* ๐Ÿ“Š *Reputation Score:* ${analysis.batchSentiment.overallScore}/100 (${analysis.batchSentiment.trend}) ๐Ÿ˜ก *Negative:* ${analysis.batchSentiment.negative} | ๐Ÿ˜Š *Positive:* ${analysis.batchSentiment.positive} *๐Ÿ”ด Crisis Signals:* ${crisisAlerts.map(a => `โ€ข [${a.severity?.toUpperCase()}] ${a.message}`).join('\n')} *๐Ÿ“ข Top Complaints:* ${analysis.topComplaintsThisRound?.slice(0, 3).map(c => `โ€ข ${c}`).join('\n') || "โ€ข None"} *โœ… Top Praises:* ${analysis.topPraisesThisRound?.slice(0, 2).map(p => `โ€ข ${p}`).join('\n') || "โ€ข None"} โฐ ${new Date().toLocaleString()} `.trim(); await axios.post( `https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage`, { chat_id: process.env.TELEGRAM_CHAT_ID, text: message, parse_mode: "Markdown" } ); }

Weekly Reputation Report

function generateWeeklyReport(weekData) { const avgScore = Math.round( weekData.reduce((sum, d) => sum + d.score, 0) / weekData.length ); const totalMentions = weekData.reduce((sum, d) => sum + d.mentions, 0); const totalNegative = weekData.reduce((sum, d) => sum + d.negative, 0); const date = new Date().toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' }); return `# ๐Ÿ“ฃ Weekly Reputation Report โ€” ${BRAND_CONFIG.brandName} **Week ending:** ${date} --- ## ๐Ÿ“Š At a Glance | Metric | Value | |---|---| | Reputation Score | ${avgScore}/100 | | Total Mentions | ${totalMentions} | | Negative Mentions | ${totalNegative} (${Math.round(totalNegative/totalMentions*100)}%) | | Crisis Events | ${weekData.filter(d => d.hadCrisis).length} | | Trend | ${avgScore >= 70 ? "โœ… Healthy" : avgScore >= 50 ? "โš ๏ธ Watch" : "๐Ÿšจ At Risk"} | --- ## ๐Ÿ“ˆ Day-by-Day Sentiment ${weekData.map(d => `**${d.date}** โ€” Score: ${d.score}/100 | Mentions: ${d.mentions} | Neg: ${d.negative}` ).join('\n')} --- ## ๐Ÿ”ด Top Complaints This Week ${weekData.flatMap(d => d.complaints || []).slice(0, 8).map(c => `- ${c}`).join('\n')} --- ## ๐ŸŸข Top Praises This Week ${weekData.flatMap(d => d.praises || []).slice(0, 5).map(p => `- ${p}`).join('\n')} --- ## ๐Ÿ’ก Recommended Actions 1. Address top recurring complaint systematically โ€” not just one-by-one 2. Amplify positive mentions by engaging with brand advocates 3. Monitor competitor sentiment for positioning opportunities --- *Generated by Social Listening Bot โ€ข Powered by Apify + Claude* `; }

Master Orchestrator โ€” Full Pipeline

import cron from 'node-cron'; import { writeFileSync } from 'fs'; async function runSocialListening() { console.log(`\n๐Ÿ‘‚ Social Listening scan โ€” ${new Date().toISOString()}`); try { // STEP 1 โ€” Scrape all platforms console.log("[1/5] Scraping mentions..."); const mentions = await scrapeAllMentions(); console.log(` โœ… ${mentions.length} mentions collected`); if (mentions.length === 0) { console.log(" โ„น๏ธ No new mentions found"); return; } // STEP 2 โ€” Analyze sentiment console.log("[2/5] Analyzing sentiment with Claude..."); const analysis = await analyzeSentiment(mentions); const score = analysis.batchSentiment.overallScore; console.log(` โœ… Score: ${score}/100 | Neg: ${analysis.batchSentiment.negative} | Trend: ${analysis.batchSentiment.trend}`); // STEP 3 โ€” Detect crisis console.log("[3/5] Checking for crisis signals..."); const crisisAlerts = detectCrisis(analysis); console.log(` โœ… ${crisisAlerts.length} crisis signal(s) detected`); // STEP 4 โ€” Generate response suggestions for urgent mentions const urgentMentions = analysis.analyzedMentions?.filter(m => m.requiresResponse && (m.urgency === "critical" || m.urgency === "high") ) || []; let responses = { suggestions: [] }; if (urgentMentions.length > 0) { console.log(`[4/5] Generating ${urgentMentions.length} response suggestions...`); responses = await generateResponseSuggestions(urgentMentions); console.log(` โœ… ${responses.suggestions?.length} response drafts ready`); } // STEP 5 โ€” Send alerts if needed if (crisisAlerts.length > 0) { console.log("[5/5] Sending crisis alerts..."); if (process.env.SLACK_WEBHOOK_URL) { await sendSlackAlert(crisisAlerts, analysis, responses); } if (process.env.TELEGRAM_BOT_TOKEN) { await sendTelegramAlert(crisisAlerts, analysis); } console.log(" โœ… Alerts sent"); } else { console.log("[5/5] No alerts needed โ€” reputation looks healthy"); } // Save report const report = { scannedAt: new Date().toISOString(), mentionsFound: mentions.length, sentimentScore: score, trend: analysis.batchSentiment.trend, crisisAlerts, topComplaints: analysis.topComplaintsThisRound, topPraises: analysis.topPraisesThisRound, responseSuggestions: responses.suggestions }; writeFileSync(`./reputation-log-${Date.now()}.json`, JSON.stringify(report, null, 2)); return report; } catch (err) { console.error("Listening error:", err.message); } } // Scan every hour cron.schedule('0 * * * *', runSocialListening); // Run immediately on startup runSocialListening();

Environment Variables

# .env APIFY_TOKEN=apify_api_xxxxxxxxxxxxxxxx CLAUDE_API_KEY=sk-ant-xxxxxxxxxxxxxxxx # Alerts SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxx/xxx/xxx TELEGRAM_BOT_TOKEN=123456789:AABBccDDeeFFggHH TELEGRAM_CHAT_ID=-1001234567890 # Optional ALERT_EMAIL=team@yourbrand.com

Normalized Mention Schema

{ "source": "twitter", "text": "Just tried YourBrand and honestly it is broken...", "author": "user123", "followers": 12400, "engagements": 847, "sentiment": "negative", "sentimentScore": 2, "emotionalTone": "frustrated", "category": "product_feedback", "urgency": "high", "requiresResponse": true, "isCrisisSignal": false, "keyTopics": ["bug", "login", "performance"], "url": "https://twitter.com/user123/status/xxx", "createdAt": "2025-02-25T09:00:00Z" }

Best Practices

Scan every 30โ€“60 minutes for real-time monitoring, every 4 hours for standard tracking Always monitor competitor brand names in parallel for benchmarking opportunities Set crisisThreshold.negativeSpike based on your normal daily volume โ€” not a fixed number Flag and ignore spam/bot mentions โ€” Claude's confidenceLevel field helps filter these Route critical alerts to on-call Slack/phone, high alerts to the team channel Use the response suggestions as drafts only โ€” always have a human review before posting Archive all mention logs for quarterly trend analysis and PR reporting

Error Handling

try { const mentions = await scrapeAllMentions(); return mentions; } catch (error) { if (error.statusCode === 401) throw new Error("Invalid Apify token"); if (error.statusCode === 429) throw new Error("Rate limit hit โ€” space out scraping intervals"); if (error.message.includes("TELEGRAM")) throw new Error("Telegram config error โ€” check token and chat ID"); throw error; }

Requirements

Apify account โ†’ https://www.apify.com/?fpr=dx06p Claude / OpenClaw API key Node.js 18+ with apify-client, axios, node-cron Slack workspace and/or Telegram bot for alerts Optional: Redis for persistent sentiment history and trend tracking across restarts

Category context

Messaging, meetings, inboxes, CRM, and teammate communication surfaces.

Source: Tencent SkillHub

Largest current source with strong distribution and engagement signals.

Package contents

Included in package
1 Docs
  • SKILL.md Primary doc