Twitter (or X, whatever we're calling it now) is where brands live and die in real-time.
One bad tweet can go viral. One good reply can land you 10,000 new followers.
But how do you know what people are actually saying about your brand when you have thousands of mentions?
In this tutorial, we'll build a Twitter Sentiment Analyzer that:
- Scrapes tweets mentioning any topic or user
- Feeds them into OpenAI (GPT-4o-mini)
- Returns sentiment breakdown + key themes
The Stack
- Node.js: Runtime
- SociaVault API: To scrape tweets (no $42,000 Twitter API needed)
- OpenAI API: To analyze sentiment
Why Not Use the Official Twitter API?
Quick math:
- Twitter Free Tier: 1,500 tweets/month (useless)
- Twitter Basic: $100/month (still limited)
- Twitter Pro: $5,000/month (finally usable)
- Twitter Enterprise: $42,000/month
SociaVault: Pay-per-request, ~$0.001/tweet
Yeah, we're using SociaVault.
Step 1: Setup
Initialize a new Node.js project:
mkdir twitter-sentiment
cd twitter-sentiment
npm init -y
npm install axios openai dotenv
Create your .env file:
SOCIAVAULT_API_KEY=your_sociavault_key
OPENAI_API_KEY=your_openai_key
Step 2: Get Tweets from a User
First, let's build a function to fetch recent tweets from any Twitter user using the /v1/scrape/twitter/user-tweets endpoint.
Create index.js:
require('dotenv').config();
const axios = require('axios');
const OpenAI = require('openai');
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const SOCIAVAULT_BASE = 'https://api.sociavault.com';
async function getUserTweets(handle) {
console.log(`π₯ Fetching tweets from @${handle}...`);
try {
const response = await axios.get(`${SOCIAVAULT_BASE}/v1/scrape/twitter/user-tweets`, {
params: { handle },
headers: { 'Authorization': `Bearer ${process.env.SOCIAVAULT_API_KEY}` }
});
const tweets = response.data.data || [];
// Extract just the text content
return tweets.map(t => ({
text: t.text,
likes: t.favorite_count || t.likes,
retweets: t.retweet_count || t.retweets,
date: t.created_at
}));
} catch (error) {
console.error('Error fetching tweets:', error.message);
return [];
}
}
Step 3: Get Tweet Details (with Engagement)
Sometimes you want to analyze a specific viral tweet and its replies. Let's add a function for that:
async function getTweetDetails(tweetUrl) {
console.log(`π₯ Fetching tweet details...`);
try {
const response = await axios.get(`${SOCIAVAULT_BASE}/v1/scrape/twitter/tweet`, {
params: { url: tweetUrl },
headers: { 'Authorization': `Bearer ${process.env.SOCIAVAULT_API_KEY}` }
});
return response.data.data;
} catch (error) {
console.error('Error fetching tweet:', error.message);
return null;
}
}
Step 4: Analyze with AI
Now let's send these tweets to OpenAI for sentiment analysis:
async function analyzeSentiment(tweets) {
console.log(`π€ Analyzing ${tweets.length} tweets with AI...`);
// Sample first 50 tweets to save tokens
const sample = tweets.slice(0, 50);
const prompt = `
Analyze the sentiment and themes of these tweets.
Return a JSON object with:
1. "sentiment": { "positive": %, "negative": %, "neutral": % }
2. "themes": Array of top 5 recurring themes/topics
3. "notable_tweets": Array of 3 most significant tweets (positive or negative)
4. "summary": 2-sentence overall analysis
Tweets:
${JSON.stringify(sample.map(t => t.text))}
`;
const completion = await openai.chat.completions.create({
messages: [{ role: "user", content: prompt }],
model: "gpt-4o-mini",
response_format: { type: "json_object" },
});
return JSON.parse(completion.choices[0].message.content);
}
Step 5: Brand Monitoring Function
Here's where it gets interesting. Let's build a function that monitors what people are saying about a specific topic or brand:
async function monitorBrand(brandHandle) {
console.log(`\nπ Monitoring brand: @${brandHandle}\n`);
// 1. Get their recent tweets
const brandTweets = await getUserTweets(brandHandle);
if (brandTweets.length === 0) {
console.log('No tweets found.');
return;
}
console.log(`β
Found ${brandTweets.length} tweets from @${brandHandle}`);
// 2. Calculate engagement metrics
const avgLikes = brandTweets.reduce((sum, t) => sum + (t.likes || 0), 0) / brandTweets.length;
const avgRetweets = brandTweets.reduce((sum, t) => sum + (t.retweets || 0), 0) / brandTweets.length;
console.log(`π Avg Engagement: ${Math.round(avgLikes)} likes, ${Math.round(avgRetweets)} retweets`);
// 3. Analyze sentiment
const analysis = await analyzeSentiment(brandTweets);
// 4. Output Results
console.log('\nπ Sentiment Analysis Report:');
console.log('βββββββββββββββββββββββββββββββ');
console.log(`Positive: ${analysis.sentiment.positive}%`);
console.log(`Neutral: ${analysis.sentiment.neutral}%`);
console.log(`Negative: ${analysis.sentiment.negative}%`);
console.log('\nπ·οΈ Top Themes:');
analysis.themes.forEach((theme, i) => {
console.log(` ${i + 1}. ${theme}`);
});
console.log('\nπ Summary:', analysis.summary);
return analysis;
}
Step 6: Putting It All Together
async function main() {
// Option 1: Analyze a specific user's tweets
await monitorBrand('vercel');
// Option 2: Analyze a specific viral tweet
// const tweet = await getTweetDetails('https://x.com/user/status/1234567890');
// console.log(tweet);
}
main();
The Result
When you run node index.js:
π Monitoring brand: @vercel
π₯ Fetching tweets from @vercel...
β
Found 48 tweets from @vercel
π Avg Engagement: 847 likes, 124 retweets
π€ Analyzing 48 tweets with AI...
π Sentiment Analysis Report:
βββββββββββββββββββββββββββββββ
Positive: 82%
Neutral: 14%
Negative: 4%
π·οΈ Top Themes:
1. Product launches and updates
2. Developer experience improvements
3. Performance and speed
4. Community engagement
5. AI and edge functions
π Summary: Vercel maintains a highly positive brand presence focused on developer experience and product innovation. The small percentage of negative sentiment relates to occasional deployment issues.
Taking It Further
This is a basic implementation. Here's how you could expand it:
1. Automated Monitoring with Cron
const cron = require('node-cron');
// Run every hour
cron.schedule('0 * * * *', async () => {
const analysis = await monitorBrand('yourcompany');
// Alert if negative sentiment spikes
if (analysis.sentiment.negative > 20) {
await sendSlackAlert('β οΈ Negative sentiment spike detected!');
}
});
2. Compare Competitors
async function compareCompetitors(handles) {
const results = {};
for (const handle of handles) {
results[handle] = await monitorBrand(handle);
}
return results;
}
// Usage
await compareCompetitors(['vercel', 'netlify', 'railway']);
3. Track Sentiment Over Time
// Store results in a database and build a trend chart
const sentimentHistory = [];
async function trackSentiment(handle) {
const analysis = await monitorBrand(handle);
sentimentHistory.push({
date: new Date(),
handle,
sentiment: analysis.sentiment
});
// Save to your database...
}
Why This Matters
Social listening tools like Brandwatch, Sprout Social, and Mention charge $300-1,000+/month.
You just built the core sentiment analysis engine in ~100 lines of code.
The API costs? Maybe $5-10/month for most use cases.
The difference? You own the code. You can customize it, integrate it with your existing systems, and scale it however you want.
Next Steps
- Get your SociaVault API Key
- Get an OpenAI API Key
- Start monitoring your brand (or your competitors)
Top comments (0)