Social Media Sentiment Analysis: Measure Brand Perception at Scale
Your brand gets mentioned 500 times today. Are people loving you or hating you?
You could read every comment manually. That takes hours and you still miss patterns. By the time you notice negative sentiment growing, it is too late.
I learned this the hard way. A product launch went viral—but not in a good way. Complaints were everywhere. We had no idea until customers started demanding refunds.
We were tracking metrics like engagement and reach. But we missed the most important signal: sentiment.
Now I measure sentiment automatically on every brand mention, every comment, every review. When negativity spikes, I know within minutes. When something resonates positively, I double down immediately.
Let me show you how to implement sentiment analysis so you never get blindsided by negative perception again.
What Sentiment Analysis Actually Measures
Sentiment analysis goes beyond counting likes and comments. It understands HOW people feel.
The Three Core Sentiments
Positive: Happy, excited, satisfied, grateful
- "This product changed my life"
- "Best purchase ever!"
- "Absolutely love this"
Negative: Angry, disappointed, frustrated, dissatisfied
- "Worst customer service"
- "Total waste of money"
- "Never buying again"
Neutral: Informational, questions, objective statements
- "What time does the sale start?"
- "Available in blue?"
- "Shipping to Canada?"
Why Neutral Matters
Most brands ignore neutral sentiment. Big mistake.
Neutral comments are opportunities. Someone asking "Is this good for beginners?" is considering a purchase. Answer well and you convert them.
Track neutral sentiment separately. High neutral means people are interested but need more information.
The Sentiment Score
Convert sentiment into a number from -1 to +1:
- +1: Extremely positive
- +0.5: Somewhat positive
- 0: Neutral
- -0.5: Somewhat negative
- -1: Extremely negative
Then calculate your average sentiment score across all mentions.
Healthy brand: +0.3 to +0.6 Warning zone: -0.1 to +0.2 Crisis zone: Below -0.1
Extract Comments for Analysis
First, get the data. Pull comments from posts, profiles, and hashtags.
Method 1: Extract Post Comments
Analyze sentiment on your own posts:
const axios = require('axios');
async function getPostComments(postId, platform = 'instagram') {
try {
const response = await axios.get(
`https://api.sociavault.com/${platform}/comments`,
{
params: {
postId: postId,
amount: 100
},
headers: {
'X-API-Key': process.env.SOCIAVAULT_API_KEY
}
}
);
return response.data.comments;
} catch (error) {
console.error('Failed to fetch comments:', error.message);
return [];
}
}
// Get comments from recent post
const comments = await getPostComments('POST_ID', 'instagram');
console.log(`Extracted ${comments.length} comments for analysis`);
Method 2: Track Brand Mentions
Find what people say about your brand in captions and comments:
async function findBrandMentions(brandName, hashtag, amount = 100) {
try {
// Get posts mentioning your brand
const response = await axios.get(
'https://api.sociavault.com/instagram/hashtag',
{
params: {
hashtag: hashtag,
amount: amount
},
headers: {
'X-API-Key': process.env.SOCIAVAULT_API_KEY
}
}
);
const posts = response.data.posts;
// Filter for brand mentions
const mentions = posts.filter(post => {
const caption = (post.caption || '').toLowerCase();
return caption.includes(brandName.toLowerCase());
});
console.log(`Found ${mentions.length} mentions of ${brandName}`);
// Get comments for each mention
const allComments = [];
for (const post of mentions.slice(0, 20)) {
const comments = await getPostComments(post.id, 'instagram');
allComments.push(...comments);
// Add the post caption as a mention too
allComments.push({
text: post.caption,
author: post.ownerUsername,
timestamp: post.timestamp
});
}
return allComments;
} catch (error) {
console.error('Failed to find brand mentions:', error.message);
return [];
}
}
// Track mentions of your brand
const mentions = await findBrandMentions('YourBrand', 'fitness');
Method 3: TikTok Comment Analysis
TikTok comments are gold for sentiment—people are brutally honest:
async function getTikTokComments(videoId) {
try {
const response = await axios.get(
'https://api.sociavault.com/tiktok/comments',
{
params: {
videoId: videoId,
amount: 200
},
headers: {
'X-API-Key': process.env.SOCIAVAULT_API_KEY
}
}
);
return response.data.comments;
} catch (error) {
console.error('Failed to fetch TikTok comments:', error.message);
return [];
}
}
const tiktokComments = await getTikTokComments('VIDEO_ID');
Analyze Sentiment
Now analyze the sentiment of each comment.
Basic Sentiment Detection
Start with a simple keyword-based approach:
function analyzeSentiment(text) {
const positiveWords = [
'love', 'amazing', 'great', 'awesome', 'excellent', 'perfect',
'best', 'fantastic', 'wonderful', 'incredible', 'brilliant',
'helpful', 'thank', 'thanks', 'grateful', 'appreciate'
];
const negativeWords = [
'hate', 'terrible', 'awful', 'worst', 'horrible', 'bad',
'disappointed', 'disappointing', 'poor', 'useless', 'waste',
'never', 'regret', 'scam', 'fraud', 'fake', 'broken'
];
const text_lower = text.toLowerCase();
let positiveCount = 0;
let negativeCount = 0;
positiveWords.forEach(word => {
if (text_lower.includes(word)) positiveCount++;
});
negativeWords.forEach(word => {
if (text_lower.includes(word)) negativeCount++;
});
// Calculate sentiment score
const totalWords = positiveCount + negativeCount;
if (totalWords === 0) {
return { sentiment: 'neutral', score: 0, confidence: 'low' };
}
const score = (positiveCount - negativeCount) / totalWords;
let sentiment;
if (score > 0.3) sentiment = 'positive';
else if (score < -0.3) sentiment = 'negative';
else sentiment = 'neutral';
return {
sentiment,
score,
confidence: totalWords >= 2 ? 'high' : 'medium',
positiveWords: positiveCount,
negativeWords: negativeCount
};
}
// Test it
const result = analyzeSentiment("This product is amazing! Best purchase ever.");
console.log(result);
// { sentiment: 'positive', score: 1, confidence: 'high' }
Advanced Sentiment with Context
Handle negations and intensifiers:
function advancedSentimentAnalysis(text) {
const positiveWords = new Set([
'love', 'amazing', 'great', 'awesome', 'excellent', 'perfect',
'best', 'fantastic', 'wonderful', 'incredible', 'brilliant',
'helpful', 'happy', 'satisfied', 'recommend', 'impressed'
]);
const negativeWords = new Set([
'hate', 'terrible', 'awful', 'worst', 'horrible', 'bad',
'disappointed', 'poor', 'useless', 'waste', 'never',
'regret', 'broken', 'angry', 'frustrated', 'annoyed'
]);
const negations = new Set(['not', 'no', 'never', "n't", 'neither', 'nobody', 'nothing']);
const intensifiers = new Set(['very', 'really', 'extremely', 'absolutely', 'completely', 'totally']);
const words = text.toLowerCase().split(/\s+/);
let score = 0;
let sentimentCount = 0;
for (let i = 0; i < words.length; i++) {
const word = words[i].replace(/[^\w]/g, '');
// Check for sentiment words
let wordScore = 0;
if (positiveWords.has(word)) wordScore = 1;
if (negativeWords.has(word)) wordScore = -1;
if (wordScore !== 0) {
sentimentCount++;
// Check for negation before this word
if (i > 0 && negations.has(words[i - 1])) {
wordScore *= -1; // Flip sentiment
}
// Check for intensifier before this word
if (i > 0 && intensifiers.has(words[i - 1])) {
wordScore *= 1.5; // Amplify sentiment
}
score += wordScore;
}
}
// Normalize score
const normalizedScore = sentimentCount > 0 ? score / sentimentCount : 0;
let sentiment;
let confidence;
if (normalizedScore > 0.4) {
sentiment = 'positive';
confidence = normalizedScore > 0.7 ? 'high' : 'medium';
} else if (normalizedScore < -0.4) {
sentiment = 'negative';
confidence = normalizedScore < -0.7 ? 'high' : 'medium';
} else {
sentiment = 'neutral';
confidence = sentimentCount > 0 ? 'medium' : 'low';
}
return {
sentiment,
score: normalizedScore,
confidence,
text: text.substring(0, 100)
};
}
// Test negation handling
console.log(advancedSentimentAnalysis("This is not bad"));
// { sentiment: 'positive', score: 1, confidence: 'medium' }
console.log(advancedSentimentAnalysis("This is not good"));
// { sentiment: 'negative', score: -1, confidence: 'medium' }
Batch Sentiment Analysis
Analyze hundreds of comments at once:
function analyzeBatchSentiment(comments) {
console.log(`\n=== ANALYZING ${comments.length} COMMENTS ===\n`);
const results = {
total: comments.length,
positive: 0,
negative: 0,
neutral: 0,
averageScore: 0,
sentiment: 'neutral',
samples: {
positive: [],
negative: [],
neutral: []
}
};
let totalScore = 0;
comments.forEach(comment => {
const text = comment.text || comment.comment || '';
const analysis = advancedSentimentAnalysis(text);
totalScore += analysis.score;
if (analysis.sentiment === 'positive') {
results.positive++;
if (results.samples.positive.length < 3) {
results.samples.positive.push(text.substring(0, 100));
}
} else if (analysis.sentiment === 'negative') {
results.negative++;
if (results.samples.negative.length < 3) {
results.samples.negative.push(text.substring(0, 100));
}
} else {
results.neutral++;
if (results.samples.neutral.length < 3) {
results.samples.neutral.push(text.substring(0, 100));
}
}
});
results.averageScore = (totalScore / comments.length).toFixed(3);
// Determine overall sentiment
if (results.averageScore > 0.2) results.sentiment = 'positive';
else if (results.averageScore < -0.2) results.sentiment = 'negative';
// Calculate percentages
const positivePercent = ((results.positive / results.total) * 100).toFixed(1);
const negativePercent = ((results.negative / results.total) * 100).toFixed(1);
const neutralPercent = ((results.neutral / results.total) * 100).toFixed(1);
console.log('SENTIMENT BREAKDOWN:');
console.log(`Positive: ${results.positive} (${positivePercent}%)`);
console.log(`Negative: ${results.negative} (${negativePercent}%)`);
console.log(`Neutral: ${results.neutral} (${neutralPercent}%)`);
console.log(`\nAverage Score: ${results.averageScore}`);
console.log(`Overall Sentiment: ${results.sentiment.toUpperCase()}`);
console.log('\nSAMPLE POSITIVE COMMENTS:');
results.samples.positive.forEach((text, i) => console.log(`${i + 1}. ${text}`));
console.log('\nSAMPLE NEGATIVE COMMENTS:');
results.samples.negative.forEach((text, i) => console.log(`${i + 1}. ${text}`));
return results;
}
// Analyze all comments
const sentimentResults = analyzeBatchSentiment(comments);
Track Sentiment Over Time
One snapshot is not enough. Track sentiment trends.
class SentimentTracker {
constructor() {
this.history = [];
}
async trackPost(postId, platform = 'instagram') {
const comments = await getPostComments(postId, platform);
const analysis = analyzeBatchSentiment(comments);
const record = {
timestamp: Date.now(),
date: new Date().toISOString(),
postId,
platform,
totalComments: analysis.total,
positive: analysis.positive,
negative: analysis.negative,
neutral: analysis.neutral,
averageScore: parseFloat(analysis.averageScore),
sentiment: analysis.sentiment
};
this.history.push(record);
return record;
}
async trackHashtag(hashtag, brandName, platform = 'instagram') {
const mentions = await findBrandMentions(brandName, hashtag);
const analysis = analyzeBatchSentiment(mentions);
const record = {
timestamp: Date.now(),
date: new Date().toISOString(),
hashtag,
brandName,
platform,
totalMentions: analysis.total,
positive: analysis.positive,
negative: analysis.negative,
neutral: analysis.neutral,
averageScore: parseFloat(analysis.averageScore),
sentiment: analysis.sentiment
};
this.history.push(record);
return record;
}
getTrend(days = 7) {
const cutoff = Date.now() - (days * 24 * 60 * 60 * 1000);
const recent = this.history.filter(r => r.timestamp > cutoff);
if (recent.length === 0) return null;
const avgScore = recent.reduce((sum, r) => sum + r.averageScore, 0) / recent.length;
const avgPositive = recent.reduce((sum, r) => sum + r.positive, 0) / recent.length;
const avgNegative = recent.reduce((sum, r) => sum + r.negative, 0) / recent.length;
// Calculate trend direction
const firstHalf = recent.slice(0, Math.floor(recent.length / 2));
const secondHalf = recent.slice(Math.floor(recent.length / 2));
const firstAvg = firstHalf.reduce((sum, r) => sum + r.averageScore, 0) / firstHalf.length;
const secondAvg = secondHalf.reduce((sum, r) => sum + r.averageScore, 0) / secondHalf.length;
const change = secondAvg - firstAvg;
let trend = 'stable';
if (change > 0.1) trend = 'improving';
if (change < -0.1) trend = 'declining';
return {
period: `${days} days`,
totalRecords: recent.length,
averageScore: avgScore.toFixed(3),
averagePositive: avgPositive.toFixed(1),
averageNegative: avgNegative.toFixed(1),
trend,
change: change.toFixed(3)
};
}
getAlerts() {
const recent = this.history.slice(-10);
const alerts = [];
// Alert if sentiment dropped suddenly
if (recent.length >= 2) {
const latest = recent[recent.length - 1];
const previous = recent[recent.length - 2];
if (latest.averageScore < -0.3 && previous.averageScore > 0) {
alerts.push({
type: 'sentiment_drop',
severity: 'high',
message: `Sentiment dropped from ${previous.averageScore.toFixed(2)} to ${latest.averageScore.toFixed(2)}`,
timestamp: latest.date
});
}
// Alert if negative comments spiking
const negativePercent = (latest.negative / latest.totalComments) * 100;
if (negativePercent > 40) {
alerts.push({
type: 'high_negativity',
severity: 'medium',
message: `${negativePercent.toFixed(1)}% negative comments on recent post`,
timestamp: latest.date
});
}
}
return alerts;
}
}
// Usage
const tracker = new SentimentTracker();
// Track sentiment daily
await tracker.trackHashtag('fitness', 'YourBrand');
// Check trend after a week
const trend = tracker.getTrend(7);
console.log('7-DAY TREND:', trend);
// Get alerts
const alerts = tracker.getAlerts();
if (alerts.length > 0) {
console.log('\n⚠️ ALERTS:');
alerts.forEach(alert => console.log(`${alert.severity.toUpperCase()}: ${alert.message}`));
}
Python Sentiment Analysis
For more sophisticated analysis with machine learning:
import requests
import pandas as pd
import matplotlib.pyplot as plt
from collections import Counter
import re
def get_comments(post_id, platform='instagram', api_key='YOUR_KEY'):
"""Fetch comments for sentiment analysis"""
url = f'https://api.sociavault.com/{platform}/comments'
response = requests.get(
url,
params={'postId': post_id, 'amount': 200},
headers={'X-API-Key': api_key}
)
return response.json()['comments']
def simple_sentiment(text):
"""Basic sentiment analysis"""
positive_words = [
'love', 'amazing', 'great', 'awesome', 'excellent', 'perfect',
'best', 'fantastic', 'wonderful', 'incredible', 'helpful'
]
negative_words = [
'hate', 'terrible', 'awful', 'worst', 'horrible', 'bad',
'disappointed', 'poor', 'useless', 'waste', 'never', 'broken'
]
text_lower = text.lower()
pos_count = sum(1 for word in positive_words if word in text_lower)
neg_count = sum(1 for word in negative_words if word in text_lower)
if pos_count > neg_count:
return 'positive', (pos_count - neg_count) / max(pos_count + neg_count, 1)
elif neg_count > pos_count:
return 'negative', -(neg_count - pos_count) / max(pos_count + neg_count, 1)
else:
return 'neutral', 0.0
def analyze_sentiment_batch(comments):
"""Analyze sentiment for batch of comments"""
results = []
for comment in comments:
text = comment.get('text', '')
sentiment, score = simple_sentiment(text)
results.append({
'text': text[:100],
'sentiment': sentiment,
'score': score,
'author': comment.get('author', 'unknown'),
'likes': comment.get('likesCount', 0)
})
df = pd.DataFrame(results)
return df
def visualize_sentiment(df):
"""Create sentiment visualizations"""
# Sentiment distribution
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# Pie chart
sentiment_counts = df['sentiment'].value_counts()
axes[0, 0].pie(sentiment_counts.values, labels=sentiment_counts.index, autopct='%1.1f%%')
axes[0, 0].set_title('Sentiment Distribution')
# Score histogram
axes[0, 1].hist(df['score'], bins=20, edgecolor='black')
axes[0, 1].set_title('Sentiment Score Distribution')
axes[0, 1].set_xlabel('Score')
axes[0, 1].set_ylabel('Frequency')
# Sentiment by likes
sentiment_likes = df.groupby('sentiment')['likes'].mean()
axes[1, 0].bar(sentiment_likes.index, sentiment_likes.values)
axes[1, 0].set_title('Average Likes by Sentiment')
axes[1, 0].set_ylabel('Average Likes')
# Box plot of scores
df.boxplot(column='score', by='sentiment', ax=axes[1, 1])
axes[1, 1].set_title('Score Distribution by Sentiment')
axes[1, 1].set_xlabel('Sentiment')
axes[1, 1].set_ylabel('Score')
plt.tight_layout()
plt.savefig('sentiment_analysis.png', dpi=300)
print("\nVisualization saved as sentiment_analysis.png")
def print_sentiment_report(df):
"""Print detailed sentiment report"""
total = len(df)
positive = len(df[df['sentiment'] == 'positive'])
negative = len(df[df['sentiment'] == 'negative'])
neutral = len(df[df['sentiment'] == 'neutral'])
avg_score = df['score'].mean()
print("\n" + "="*50)
print("SENTIMENT ANALYSIS REPORT")
print("="*50)
print(f"\nTotal Comments: {total}")
print(f"Positive: {positive} ({positive/total*100:.1f}%)")
print(f"Negative: {negative} ({negative/total*100:.1f}%)")
print(f"Neutral: {neutral} ({neutral/total*100:.1f}%)")
print(f"\nAverage Sentiment Score: {avg_score:.3f}")
# Overall sentiment
if avg_score > 0.2:
overall = "POSITIVE ✅"
elif avg_score < -0.2:
overall = "NEGATIVE ⚠️"
else:
overall = "NEUTRAL ⚖️"
print(f"Overall Sentiment: {overall}")
# Most positive comments
print("\n" + "-"*50)
print("TOP 3 MOST POSITIVE COMMENTS:")
print("-"*50)
top_positive = df[df['sentiment'] == 'positive'].nlargest(3, 'score')
for i, row in top_positive.iterrows():
print(f"\n{row['text']}")
print(f"Score: {row['score']:.2f} | Likes: {row['likes']}")
# Most negative comments
print("\n" + "-"*50)
print("TOP 3 MOST NEGATIVE COMMENTS:")
print("-"*50)
top_negative = df[df['sentiment'] == 'negative'].nsmallest(3, 'score')
for i, row in top_negative.iterrows():
print(f"\n{row['text']}")
print(f"Score: {row['score']:.2f} | Likes: {row['likes']}")
# Usage
api_key = 'YOUR_API_KEY'
comments = get_comments('POST_ID', 'instagram', api_key)
df = analyze_sentiment_batch(comments)
print_sentiment_report(df)
visualize_sentiment(df)
Real Brand Sentiment Examples
Let me show you what sentiment tracking reveals.
Example 1: Product Launch Gone Wrong
Brand: Tech Gadget Company
- Launch day sentiment: +0.4 (positive)
- Week 1 sentiment: -0.3 (negative)
- Issue detected: Battery life complaints (mentioned in 60% of negative comments)
- Action: Issued software update, addressed complaints publicly
- Week 2 sentiment: +0.1 (recovered to neutral)
Example 2: Viral Success
Brand: Skincare Brand
- Normal sentiment: +0.3
- Influencer partnership post sentiment: +0.7
- Insight: "before/after" format drove positive sentiment
- Action: Created more transformation content
- Sustained sentiment: +0.5 (66% improvement)
Example 3: Crisis Averted
Brand: Restaurant Chain
- Detected sentiment drop: +0.4 to -0.2 in one day
- Investigation: Food poisoning rumor spreading
- Action: Immediate response with health inspection results
- Sentiment recovery: Back to +0.3 within 48 hours
Sentiment tracking caught the issue early. Without it, the rumor would have spread for days.
Your Sentiment Action Plan
- Set up daily sentiment tracking on all brand mentions
- Create sentiment alerts for drops above 0.3 points
- Analyze negative comments to find recurring issues
- Respond to negative sentiment within 24 hours
- Double down on positive sentiment - more of what works
Get your SociaVault API key and start tracking sentiment today. Know how people feel about your brand before it becomes a problem.
Stop guessing. Start measuring.
Found this helpful?
Share it with others who might benefit
Ready to Try SociaVault?
Start extracting social media data with our powerful API