A brand crisis doesn't start on the front page of the New York Times. It starts in a Reddit thread or a viral Tweet.
If you're managing a brand, finding out about a PR disaster 12 hours after it happens is too late. You need to know the moment negative sentiment spikes.
In this tutorial, we'll build a Node.js script that monitors Reddit and Twitter (X) for mentions of your brand, runs sentiment analysis on the posts, and sends a Slack/Discord webhook alert if a highly negative post starts gaining traction.
The Architecture
- Data Ingestion: Fetch recent posts mentioning the brand from Reddit and Twitter.
- Sentiment Analysis: Use a lightweight NLP library to score the text.
- Threshold Logic: Check if the sentiment is negative AND the engagement (upvotes/likes) is high.
- Alerting: Send a webhook to Slack.
Prerequisites
- Node.js
- A Slack Workspace (for the webhook URL)
- SociaVault API Key (to fetch Reddit and Twitter data without dealing with expensive enterprise API tiers).
npm install axios sentiment dotenv
Step 1: Fetching the Data
We'll use SociaVault to search both platforms.
require('dotenv').config();
const axios = require('axios');
const Sentiment = require('sentiment');
const API_KEY = process.env.SOCIAVAULT_API_KEY;
const BASE_URL = 'https://api.sociavault.com/v1';
const sentiment = new Sentiment();
async function fetchMentions(brandName) {
const headers = { 'Authorization': `Bearer ${API_KEY}` };
let mentions = [];
try {
// 1. Fetch Reddit Mentions
const redditRes = await axios.get(`${BASE_URL}/reddit/search`, {
headers, params: { query: brandName, sort: 'new', limit: 10 }
});
const redditPosts = redditRes.data.data.map(post => ({
platform: 'Reddit',
text: `${post.title} ${post.selftext}`,
url: `https://reddit.com${post.permalink}`,
engagement: post.score,
author: post.author
}));
mentions.push(...redditPosts);
// 2. Fetch Twitter Mentions
const twitterRes = await axios.get(`${BASE_URL}/twitter/search/recent`, {
headers, params: { query: brandName, limit: 10 }
});
const tweets = twitterRes.data.data.map(tweet => ({
platform: 'Twitter',
text: tweet.text,
url: `https://twitter.com/user/status/${tweet.id}`,
engagement: tweet.public_metrics.retweet_count + tweet.public_metrics.like_count,
author: tweet.author_id
}));
mentions.push(...tweets);
} catch (error) {
console.error("Error fetching data:", error.message);
}
return mentions;
}
Step 2: Analyzing Sentiment
We'll use the sentiment npm package. It assigns a score to text. Negative numbers mean negative sentiment (e.g., -5 is very bad).
function analyzeMentions(mentions) {
const alerts = [];
mentions.forEach(mention => {
const result = sentiment.analyze(mention.text);
// CRISIS CRITERIA:
// 1. Sentiment score is highly negative (<= -3)
// 2. Engagement is gaining traction (> 50 likes/upvotes)
if (result.score <= -3 && mention.engagement > 50) {
alerts.push({
...mention,
sentimentScore: result.score,
negativeWords: result.negative
});
}
});
return alerts;
}
Step 3: Sending the Slack Alert
If our criteria are met, we fire off a webhook to Slack.
async function sendSlackAlert(alerts, webhookUrl) {
if (alerts.length === 0) return;
for (const alert of alerts) {
const payload = {
blocks: [
{
type: "header",
text: {
type: "plain_text",
text: `🚨 BRAND CRISIS ALERT: ${alert.platform}`,
emoji: true
}
},
{
type: "section",
text: {
type: "mrkdwn",
text: `*Negative sentiment detected with high engagement!*\n\n*Text:* "${alert.text.substring(0, 150)}..."\n\n*Engagement:* ${alert.engagement}\n*Sentiment Score:* ${alert.sentimentScore}\n*Trigger Words:* ${alert.negativeWords.join(', ')}`
}
},
{
type: "section",
text: {
type: "mrkdwn",
text: `<${alert.url}|View Post>`
}
}
]
};
try {
await axios.post(webhookUrl, payload);
console.log(`Alert sent for ${alert.platform} post.`);
} catch (e) {
console.error("Failed to send Slack alert");
}
}
}
Step 4: The Cron Job
Wrap it in a function and run it on an interval (e.g., every 15 minutes).
const BRAND_NAME = "YourBrandName";
const SLACK_WEBHOOK = process.env.SLACK_WEBHOOK_URL;
async function runMonitor() {
console.log(`[${new Date().toISOString()}] Running crisis monitor for ${BRAND_NAME}...`);
const mentions = await fetchMentions(BRAND_NAME);
const alerts = analyzeMentions(mentions);
if (alerts.length > 0) {
console.log(`Found ${alerts.length} potential crisis posts! Sending alerts...`);
await sendSlackAlert(alerts, SLACK_WEBHOOK);
} else {
console.log("All clear. No crisis detected.");
}
}
// Run immediately, then every 15 minutes
runMonitor();
setInterval(runMonitor, 15 * 60 * 1000);
Why This is Powerful
By combining Reddit and Twitter, you cover the two platforms where viral outrage usually begins.
Historically, building this required paying $5,000+/month for Twitter Enterprise API access and dealing with Reddit's strict rate limits.
By using SociaVault, you get a unified, affordable API that handles the scraping, proxies, and rate limits for you. You just write the business logic.
Get your free API key at SociaVault.com and protect your brand today.
Top comments (0)