Sentiment analysis
Find the conversation about a topic on YouTube and Reddit, pull the comments, and score each comment's sentiment with a model you run. From 200 credits per run.
This recipe measures public mood around a topic in three steps: locate the posts where it is discussed, collect the comments on the most active ones, and score the sentiment of those comments. The API returns the comments; the scoring runs on your side, so you choose the model and can change it without changing the data.
Cost per run
200 to 630 credits. Two searches (YouTube 10–150, Reddit 10–300), three YouTube comment pages (10 each) and three Reddit comment trees (50 each). Scoring the comments costs nothing on the API side. The Reddit leg costs the most because each call returns a whole discussion with nested replies expanded, not one page.
How do you analyze social media sentiment with an API?
Two stages. Search finds the posts where the topic is being discussed. The comment endpoints then return what people said under them, one comment per item with its text in comment.text. Score each text with a sentiment model and count the results, and you have a sentiment split.
Sentiment lives in comments, not in posts. The post says "we changed our pricing". The comments say what people think of it.
What you need
| Endpoint | Role | Credits |
|---|---|---|
GET /v1/youtube/search | Find videos about the topic | 10–150 |
GET /v1/reddit/search | Find Reddit threads about the topic | 10–300 |
GET /v1/youtube/video/comments | Top-level comments on a video | 10 |
GET /v1/reddit/post/comments | A thread's full comment tree, replies nested in comment.replies | 50 |
The code uses VADER in Python (pip install vaderSentiment requests) and the sentiment package in Node.js (npm install sentiment). Both are small English word lists that run offline. Swap in any model you prefer: a multilingual transformer, or a language model with a prompt that names your topic.
The code
# sentiment.py
# Collects comments about a topic and counts the sentiment split.
# Run with: INSIGHTSOCIAL_API_KEY=isk_live_... python sentiment.py
import os
from collections import Counter
from concurrent.futures import ThreadPoolExecutor
import requests
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
KEY = os.environ["INSIGHTSOCIAL_API_KEY"]
BASE = "https://api.insightsocial.app/v1"
TOPIC = "github copilot pricing"
KEYWORDS = ["copilot"] # a result must mention one of these to count as on-topic
THREADS_PER_PLATFORM = 3
analyzer = SentimentIntensityAnalyzer()
def get(path, **params):
res = requests.get(f"{BASE}/{path}", params=params,
headers={"x-api-key": KEY}, timeout=120)
return res.json()
def on_topic(post):
text = (post["content"]["text"] or "").lower()
return any(k in text for k in KEYWORDS)
def band(text):
# VADER's usual cut-offs on the compound score, from -1 to 1.
score = analyzer.polarity_scores(text)["compound"]
return "negative" if score <= -0.05 else "positive" if score >= 0.05 else "neutral"
def flatten_thread(comments):
# Reddit nests replies inside each comment; other platforms leave `replies` null.
for c in comments:
yield c
yield from flatten_thread(c["replies"] or [])
# Step 1: find the conversation on both platforms, keeping on-topic results.
yt = get("youtube/search", query=TOPIC)
rd = get("reddit/search", query=TOPIC, timeframe="month")
def top_urls(body, keep=lambda url: True):
if not body["success"]:
return []
posts = [i["post"] for i in body["data"]["items"]]
return [p["url"] for p in posts if p["url"] and keep(p["url"]) and on_topic(p)][:THREADS_PER_PLATFORM]
videos = top_urls(yt, keep=lambda u: "watch?v=" in u)
threads = top_urls(rd)
# Step 2: pull the comments under the top results.
jobs = [("youtube/video/comments", u) for u in videos] + \
[("reddit/post/comments", u) for u in threads]
with ThreadPoolExecutor(max_workers=6) as pool:
pages = list(pool.map(lambda j: (j, get(j[0], url=j[1])), jobs))
# Step 3: score every comment and count the split per platform.
split = {"youtube": Counter(), "reddit": Counter()}
spent = yt.get("credits_used", 0) + rd.get("credits_used", 0)
for (path, url), body in pages:
spent += body.get("credits_used", 0)
if not body["success"]:
continue
platform = path.split("/")[0]
for c in flatten_thread(item["comment"] for item in body["data"]["items"]):
# The scorer is English-only. `language` is often null; keep those.
if not c["text"] or c["language"] not in (None, "en"):
split[platform]["skipped"] += 1
continue
split[platform][band(c["text"])] += 1
for platform, counts in split.items():
print(platform, dict(counts))
print(f"credits used: {spent}")What you get back
youtube {'negative': 212, 'neutral': 96, 'positive': 71}
reddit {'negative': 88, 'neutral': 54, 'positive': 40, 'skipped': 3}
credits used: 260The figures are illustrative. skipped counts comments with no text, or tagged with a language other than English.
Where a word list stops
A word-list scorer judges how a comment feels, not how it feels about your topic in particular. A comment that is angry about a bug in a competing product still reads as negative, and sarcasm reads as praise. When you need sentiment toward one named thing, hand the comment text to a model you run with a prompt that names the topic.
The same comments are worth reading for more than polarity. Counting comments that ask a question (a ?, or "how do I") or mention cancelling is often a sharper signal than "38% negative".
What to change
TOPICandKEYWORDS. Any brand, product, feature or announcement.KEYWORDSdrops search results that only share a word with the topic.- How deep to go.
THREADS_PER_PLATFORMsets most of the price. At 3 per platform the floor is 200 credits. At 1 per platform it is 80. - Other platforms. Swap in
tiktok/searchwithtiktok/post/comments(10–30),twitter/search/tweetswithtwitter/tweet/replies(10), orinstagram/search/reelswithinstagram/post/comments(50–150). Every comment list returns the samecommentshape. - Other languages. Comments carry
comment.languagewhen the platform states it. Route each language to a model that reads it, instead of skipping it. - A fixed window. Use
timeframeon Reddit andmax_age_dayson the searches to cover a launch week.
Related
Brand mention monitoring
Run a daily brand-mention sweep across the search endpoints of six platforms in parallel, drop off-topic rows with a keyword check, dedupe against earlier runs and alert on what is new. From 60 credits per sweep.
Competitor tracking
Snapshot a competitor's followers, engagement and latest posts on TikTok, Instagram, YouTube and X in one parallel sweep, then diff it against the last run. 80 to 210 credits per competitor.