YouTubers obsess over comments.
Which is funny, because most creator tools focus on views, subscribers, and watch timeβnot what people are actually saying.
In this tutorial, we'll build a YouTube Comment Analyzer that:
- Fetches all comments from any video
- Analyzes sentiment and extracts themes
- Identifies your biggest fans (and trolls)
This is the same analysis that agencies charge creators hundreds of dollars for.
The Problem with YouTube's Data API
YouTube's API is... okay. But:
- Rate limits that make bulk analysis painful
- Complex OAuth setup
- Comments are spread across multiple nested API calls
SociaVault's comments endpoint gives you everything in one call.
The Stack
- Node.js: Runtime
- SociaVault API: To fetch comments
- OpenAI API: For sentiment analysis
- Express.js: Simple web dashboard (optional)
Step 1: Setup
mkdir youtube-comment-analyzer
cd youtube-comment-analyzer
npm init -y
npm install axios openai dotenv express
Create .env:
SOCIAVAULT_API_KEY=your_sociavault_key
OPENAI_API_KEY=your_openai_key
Step 2: Fetch Video Comments
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 getVideoComments(videoUrl) {
console.log('π₯ Fetching comments...');
try {
const response = await axios.get(`${SOCIAVAULT_BASE}/v1/scrape/youtube/video/comments`, {
params: { url: videoUrl },
headers: { 'Authorization': `Bearer ${process.env.SOCIAVAULT_API_KEY}` }
});
const comments = response.data.data || [];
console.log(`β
Fetched ${comments.length} comments`);
return comments.map(c => ({
author: c.author || c.authorDisplayName,
text: c.text || c.textDisplay,
likes: c.likeCount || c.likes || 0,
published: c.publishedAt || c.published,
replies: c.replyCount || c.totalReplyCount || 0
}));
} catch (error) {
console.error('Error fetching comments:', error.message);
return [];
}
}
Step 3: Get Video Metadata
It helps to have context about the video itself:
async function getVideoInfo(videoUrl) {
console.log('π₯ Fetching video info...');
try {
const response = await axios.get(`${SOCIAVAULT_BASE}/v1/scrape/youtube/video`, {
params: { url: videoUrl },
headers: { 'Authorization': `Bearer ${process.env.SOCIAVAULT_API_KEY}` }
});
const video = response.data.data;
return {
title: video.title,
channel: video.channelTitle || video.channel,
views: video.viewCount || video.views,
likes: video.likeCount || video.likes,
published: video.publishedAt
};
} catch (error) {
console.error('Error fetching video info:', error.message);
return null;
}
}
Step 4: AI-Powered Analysis
Now the fun partβlet's analyze those comments:
async function analyzeComments(comments, videoTitle) {
console.log('π€ Analyzing with AI...');
// Sample for large comment sections
const sample = comments.slice(0, 100);
const prompt = `
Analyze these YouTube comments for the video "${videoTitle}".
Return a JSON object with:
{
"sentiment": {
"positive": percentage,
"negative": percentage,
"neutral": percentage
},
"themes": [top 5 themes or topics people are discussing],
"questions": [top 3 questions viewers are asking],
"suggestions": [top 3 content suggestions from viewers],
"topFans": [names of 3 most engaged/positive commenters],
"criticalFeedback": [top 3 constructive criticisms],
"viralPotential": [3 comments that could be highlighted/pinned],
"summary": "2-3 sentence overall analysis"
}
Comments:
${JSON.stringify(sample.map(c => ({ author: c.author, text: c.text, likes: c.likes })))}
`;
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }],
response_format: { type: 'json_object' }
});
return JSON.parse(completion.choices[0].message.content);
}
Step 5: Find Video Ideas from Comments
YouTube comments are goldmines for content ideas:
async function findVideoIdeas(comments) {
console.log('π‘ Extracting video ideas...');
const prompt = `
These are comments from a YouTube video. Extract potential video ideas.
Look for:
- Questions that could be full videos
- Requests for related content
- Confusion that needs clarification
- Popular sub-topics worth expanding
Return JSON:
{
"videoIdeas": [
{
"title": "suggested video title",
"reason": "why this would perform well",
"basedOn": "the comment that inspired this"
}
]
}
Comments:
${JSON.stringify(comments.slice(0, 75).map(c => c.text))}
`;
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }],
response_format: { type: 'json_object' }
});
return JSON.parse(completion.choices[0].message.content);
}
Step 6: The Main Analysis Function
async function analyzeVideo(videoUrl) {
console.log('\n㪠YouTube Comment Analyzer\n');
console.log('βββββββββββββββββββββββββββββββββββββββ\n');
// 1. Get video info
const video = await getVideoInfo(videoUrl);
if (video) {
console.log(`πΉ ${video.title}`);
console.log(`πΊ ${video.channel}`);
console.log(`ποΈ ${Number(video.views).toLocaleString()} views | π ${Number(video.likes).toLocaleString()} likes\n`);
}
// 2. Get comments
const comments = await getVideoComments(videoUrl);
if (comments.length === 0) {
console.log('No comments found.');
return;
}
// 3. Calculate basic metrics
const totalLikes = comments.reduce((sum, c) => sum + (c.likes || 0), 0);
const avgLikes = (totalLikes / comments.length).toFixed(1);
const topComment = comments.reduce((max, c) => c.likes > max.likes ? c : max, comments[0]);
console.log(`π¬ ${comments.length} comments analyzed`);
console.log(`β€οΈ ${totalLikes.toLocaleString()} total comment likes (avg: ${avgLikes})`);
console.log(`π Top comment: "${topComment.text.substring(0, 50)}..." (${topComment.likes} likes)\n`);
// 4. AI Analysis
const analysis = await analyzeComments(comments, video?.title || 'Unknown');
console.log('βββββββββββββββββββββββββββββββββββββββ');
console.log('π SENTIMENT ANALYSIS');
console.log('βββββββββββββββββββββββββββββββββββββββ\n');
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β Questions from Viewers:');
analysis.questions.forEach((q, i) => {
console.log(` ${i + 1}. ${q}`);
});
console.log('\nπ‘ Content Suggestions:');
analysis.suggestions.forEach((s, i) => {
console.log(` ${i + 1}. ${s}`);
});
console.log('\nβ Your Top Fans:');
analysis.topFans.forEach((fan, i) => {
console.log(` ${i + 1}. ${fan}`);
});
console.log('\nπ Summary:', analysis.summary);
// 5. Video Ideas (bonus)
const ideas = await findVideoIdeas(comments);
console.log('\nβββββββββββββββββββββββββββββββββββββββ');
console.log('π‘ VIDEO IDEAS FROM COMMENTS');
console.log('βββββββββββββββββββββββββββββββββββββββ\n');
ideas.videoIdeas.forEach((idea, i) => {
console.log(`${i + 1}. "${idea.title}"`);
console.log(` Why: ${idea.reason}`);
console.log(` Based on: "${idea.basedOn.substring(0, 50)}..."\n`);
});
return { video, comments, analysis, ideas };
}
Step 7: Run It
async function main() {
const videoUrl = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'; // Replace with any video
await analyzeVideo(videoUrl);
}
main();
Sample Output
π¬ YouTube Comment Analyzer
βββββββββββββββββββββββββββββββββββββββ
πΉ How to Build a SaaS in 2024
πΊ TechWithTim
ποΈ 245,892 views | π 12,453 likes
π₯ Fetching comments...
β
Fetched 847 comments
π¬ 847 comments analyzed
β€οΈ 5,234 total comment likes (avg: 6.2)
π Top comment: "This is exactly what I needed! Been stru..." (234 likes)
π€ Analyzing with AI...
βββββββββββββββββββββββββββββββββββββββ
π SENTIMENT ANALYSIS
βββββββββββββββββββββββββββββββββββββββ
β
Positive: 78%
π Neutral: 17%
β Negative: 5%
π·οΈ Top Themes:
1. Appreciation for step-by-step format
2. Questions about specific tech stack choices
3. Requests for follow-up on deployment
4. Comparisons to other tutorials
5. Pricing and monetization questions
β Questions from Viewers:
1. Can you do a video on adding Stripe integration?
2. How does this scale with more users?
3. What about authentication best practices?
π‘ Content Suggestions:
1. Series on adding payment processing
2. Deep dive into database optimization
3. Video on marketing the finished SaaS
β Your Top Fans:
1. @CodeWithChris
2. @DevMike
3. @SarahCodes
π Summary: Viewers are overwhelmingly positive about the tutorial format and pacing. The main areas of confusion center around deployment and scaling, suggesting strong demand for follow-up content.
βββββββββββββββββββββββββββββββββββββββ
π‘ VIDEO IDEAS FROM COMMENTS
βββββββββββββββββββββββββββββββββββββββ
1. "From Zero to Stripe: Adding Payments to Your SaaS"
Why: 47 comments mentioned payment integration
Based on: "Great video! Now how do I actually charge people..."
2. "Scaling Node.js: From 100 to 100,000 Users"
Why: Performance questions indicate intermediate audience ready for advanced content
Based on: "What happens when this gets real traffic..."
3. "SaaS Authentication Deep Dive (OAuth, Magic Links, Sessions)"
Why: Authentication confusion is a clear knowledge gap
Based on: "I'm confused about the auth part. Can you..."
Taking It Further
1. Simple Web Dashboard
const express = require('express');
const app = express();
app.get('/analyze', async (req, res) => {
const { url } = req.query;
if (!url) {
return res.status(400).json({ error: 'URL required' });
}
const result = await analyzeVideo(url);
res.json(result);
});
app.listen(3000, () => {
console.log('Dashboard running on http://localhost:3000');
});
2. Compare Multiple Videos
async function compareVideos(urls) {
const results = [];
for (const url of urls) {
const analysis = await analyzeVideo(url);
results.push(analysis);
}
// Compare sentiment across videos
console.log('\nπ Sentiment Comparison:');
results.forEach((r, i) => {
console.log(`${i + 1}. ${r.video.title}`);
console.log(` Positive: ${r.analysis.sentiment.positive}%`);
});
return results;
}
3. Automated Weekly Reports
const cron = require('node-cron');
// Run every Monday at 9am
cron.schedule('0 9 * * 1', async () => {
const channelVideos = await getChannelVideos(channelUrl);
const latestVideo = channelVideos[0];
const analysis = await analyzeVideo(latestVideo.url);
await sendEmailReport(analysis);
});
What You Just Built
This is the core of what VidIQ and TubeBuddy charge $50+/month for.
Except:
- You own the code
- You can customize the analysis prompts
- You can integrate it with your own tools
- It costs maybe $2-5/month to run
Get Started
- Get your SociaVault API Key
- Get an OpenAI API Key
- Paste in any YouTube URL
- Start understanding your audience
Your comments section is full of gold. Start mining it.
Top comments (0)