Reddit sentiment analysis means collecting what people say about a topic on Reddit and scoring each comment as positive, negative or neutral. In Python that's three steps: search Reddit for posts about the topic, fetch their comments, and score the comments with a sentiment model such as VADER. This guide builds all three and ends with a script that saves a scored CSV and prints a summary.
What you'll build
A script that takes a topic, say "framework laptop", and:
- finds the month's top Reddit posts about it,
- fetches the top comments of each post,
- scores every comment from -1 (negative) to +1 (positive),
- prints the share of positive, neutral and negative comments, and the strongest of each,
- saves everything to a CSV for a spreadsheet or a notebook.
Setup
Install the two packages:
pip install requests vaderSentimentGet an API key (Social Parse gives new accounts 100 free credits) and set it with the base URL:
export API_KEY="your-api-key"
export API_URL="https://api.socialparse.dev"VADER is a rule-based model tuned for social media text: it understands capitals, exclamation marks, emoji and slang, needs no training, and runs instantly on a laptop.
Step 1: find posts about the topic
The search endpoint returns posts from all of Reddit. sort=top with time=month gives
the posts people engaged with most in the last month:
import os
import requests
API_URL = os.environ["API_URL"]
HEADERS = {"x-api-key": os.environ["API_KEY"]}
def get(path, params=None):
response = requests.get(f"{API_URL}{path}", params=params, headers=HEADERS, timeout=120)
body = response.json()
if not response.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
return body
posts = get("/v1/reddit/search", {"q": "framework laptop", "sort": "top", "time": "month"})["data"]To stay inside one community, use subreddit post search instead:
/v1/reddit/subreddits/search?subreddit=framework&q=battery.
Step 2: fetch the comments
Post comments returns a post's comments; sort=top puts the most upvoted first:
comments = []
for post in posts[:10]:
if not post["comment_count"]:
continue
for comment in get("/v1/reddit/posts/comments", {"post_id": post["id"], "sort": "top"})["data"]:
if comment["text"]:
comment["post_title"] = post["title"]
comments.append(comment)Each comment has its text, score (upvotes minus downvotes), depth (0 for a top-level comment) and created_at.
Step 3: score each comment with VADER
VADER's compound score runs from -1 to +1. The usual cut-offs are +0.05 and -0.05:
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
analyzer = SentimentIntensityAnalyzer()
def label(compound):
if compound >= 0.05:
return "positive"
if compound <= -0.05:
return "negative"
return "neutral"
for comment in comments:
comment["compound"] = analyzer.polarity_scores(comment["text"])["compound"]
comment["sentiment"] = label(comment["compound"])Step 4: summarize
counts = {"positive": 0, "neutral": 0, "negative": 0}
for comment in comments:
counts[comment["sentiment"]] += 1
total = len(comments)
for sentiment, count in counts.items():
print(f"{sentiment:>8}: {count:4} ({count / total:.0%})")
by_score = sorted(comments, key=lambda comment: comment["compound"])
print("\nMost negative:", by_score[0]["text"][:200])
print("Most positive:", by_score[-1]["text"][:200])A raw count treats a comment with 2 upvotes the same as one with 2,000. To weigh agreement, add up each comment's
max(score, 1) per label instead of counting it once.
The full script
import csv
import os
import sys
import requests
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
API_URL = os.environ["API_URL"]
HEADERS = {"x-api-key": os.environ["API_KEY"]}
analyzer = SentimentIntensityAnalyzer()
def get(path, params=None):
response = requests.get(f"{API_URL}{path}", params=params, headers=HEADERS, timeout=120)
body = response.json()
if not response.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
return body
def label(compound):
if compound >= 0.05:
return "positive"
if compound <= -0.05:
return "negative"
return "neutral"
def main(topic, max_posts=10):
posts = get("/v1/reddit/search", {"q": topic, "sort": "top", "time": "month"})["data"]
rows = []
for post in posts[:max_posts]:
if not post["comment_count"]:
continue
for comment in get("/v1/reddit/posts/comments", {"post_id": post["id"], "sort": "top"})["data"]:
if not comment["text"]:
continue
compound = analyzer.polarity_scores(comment["text"])["compound"]
rows.append({
"post": post["title"],
"subreddit": post["subreddit"],
"comment_url": comment["url"],
"score": comment["score"],
"compound": compound,
"sentiment": label(compound),
"text": comment["text"],
})
counts = {"positive": 0, "neutral": 0, "negative": 0}
for row in rows:
counts[row["sentiment"]] += 1
print(f"{len(rows)} comments on {topic!r}")
for sentiment, count in counts.items():
print(f"{sentiment:>8}: {count:4} ({count / max(len(rows), 1):.0%})")
with open("sentiment.csv", "w", newline="", encoding="utf-8") as file:
writer = csv.DictWriter(file, fieldnames=list(rows[0]) if rows else ["text"])
writer.writeheader()
writer.writerows(rows)
if __name__ == "__main__":
main(sys.argv[1])python sentiment.py "framework laptop"What it costs
One credit for the search page, plus one per post's comments: ten posts cost 11 credits. Run it weekly on five topics and it's about 55 credits a week. Errors cost nothing. See Credits and pricing.
Making the analysis better
- Sarcasm and domain words. VADER reads "this battery is sick" as negative. For more accuracy, swap in a
transformer such as
cardiffnlp/twitter-roberta-base-sentiment-latestfrom Hugging Face, or ask an LLM to label comments with a reason. - Aspects, not just tone. Count mentions of features ("battery", "keyboard", "price") in negative comments to see what people complain about.
- Trends. Save each run with its date and chart the share of negative comments week by week.
- More platforms. TikTok comments come in the same envelope, with a
textfield too: see the TikTok comments guide.
FAQ
What's the best Python library for Reddit sentiment analysis?
VADER is the quickest start: no training, fast, and tuned for social media. For higher accuracy on nuanced text, use a transformer model or an LLM.
Do I need Reddit API credentials?
No. Social Parse reads public Reddit pages with one API key: no Reddit app, OAuth or approval. See the Reddit API pricing guide for how the official API compares.
Can I analyze a single subreddit?
Yes: use subreddit posts (sort=top&time=month) or
subreddit post search to collect posts, then the same comment and scoring
steps.
How many comments do I need?
A few hundred comments give a stable read on a topic. Fewer than 50 and a single thread can swing the result.