reddit-api
Reddit API with PRAW (Python) and Snoowrap (Node.js)
pinned to #e8b4af6updated 2 weeks ago
Ask your AI client: “install skills/reddit-api”.
Requires the metahub MCP server installed in your client. Set up MCP.
mh install skills/reddit-apimetahub onboarded this repo on the author's behalf.
If you own github.com/alinaqi/maggy on GitHub, claim the listing to take over publishing. Your claim preserves the existing eval history and badges; only the curator label is replaced with verified-publisher on your next publish.
Stars
702
Last commit
2 weeks ago
Latest release
published
- #ai-coding
- #claude
- #claude-code
- #developer-tools
- #project-initialization
- #python
- #react
- #security
- #typescript
About this skill
Pulled from SKILL.md at publish time.
For integrating Reddit data into applications - fetching posts, comments, subreddits, and user data.
Evaluation report
WarningsAutomated checks the publisher passed at publish time — structure, docs, safety, and whether the artifact behaves as claimed.e8b4af6· 2 weeks ago
Documentation
41Description qualitywarn
8 words · 52 chars — skills use the description as their trigger; aim higher
Aim for 15+ words and include trigger phrases like “use this skill when …”.
README is present and substantial
12,261 chars · 14 sections · 10 code blocks
Tags / topics declared
9 total — ai-coding, claude, claude-code, developer-tools, project-initialization, python (+3)
README has usage / example sections
no labeled section but 10 code blocks document usage
Homepage / docs URL declared
https://www.srooter.ai
Release history
1- releasecurrente8b4af6warn2 weeks ago
Contents
For integrating Reddit data into applications - fetching posts, comments, subreddits, and user data.
Sources: Reddit API Docs | OAuth2 Wiki | PRAW Docs
Setup
1. Create Reddit App
- Go to https://www.reddit.com/prefs/apps
- Click "Create App" or "Create Another App"
- Fill in:
- Name: Your app name
- App type:
script- For personal use / bots you controlweb app- For server-side apps with user authinstalled app- For mobile/desktop apps
- Redirect URI:
http://localhost:8000/callback(for dev)
- Note your
client_id(under app name) andclient_secret
2. Environment Variables
# .env
REDDIT_CLIENT_ID=your_client_id
REDDIT_CLIENT_SECRET=your_client_secret
REDDIT_USER_AGENT=YourApp/1.0 by YourUsername
REDDIT_USERNAME=your_username # For script apps only
REDDIT_PASSWORD=your_password # For script apps only
User-Agent Format: <platform>:<app_id>:<version> (by /u/<username>)
Rate Limits
| Tier | Limit | Notes |
|---|---|---|
| OAuth authenticated | 100 QPM | Per OAuth client ID |
| Non-authenticated | Blocked | Must use OAuth |
- Limits averaged over 10-minute window
- Include
User-Agentheader to avoid blocks - Respect
X-Ratelimit-*response headers
Python: PRAW (Recommended)
Installation
pip install praw
# or
uv add praw
Script App (Personal Use / Bots)
import praw
from pydantic_settings import BaseSettings
class RedditSettings(BaseSettings):
reddit_client_id: str
reddit_client_secret: str
reddit_user_agent: str
reddit_username: str
reddit_password: str
class Config:
env_file = ".env"
settings = RedditSettings()
reddit = praw.Reddit(
client_id=settings.reddit_client_id,
client_secret=settings.reddit_client_secret,
user_agent=settings.reddit_user_agent,
username=settings.reddit_username,
password=settings.reddit_password,
)
# Verify authentication
print(f"Logged in as: {reddit.user.me()}")
Read-Only (No User Auth)
import praw
reddit = praw.Reddit(
client_id="your_client_id",
client_secret="your_client_secret",
user_agent="YourApp/1.0 by YourUsername",
)
# Read-only mode - can browse, can't post/vote
reddit.read_only = True
Common Operations
# Get subreddit posts
subreddit = reddit.subreddit("python")
# Hot posts
for post in subreddit.hot(limit=10):
print(f"{post.title} - {post.score} upvotes")
# New posts
for post in subreddit.new(limit=10):
print(post.title)
# Search posts
for post in subreddit.search("pydantic", limit=5):
print(post.title)
# Get specific post
submission = reddit.submission(id="abc123")
print(submission.title)
print(submission.selftext)
# Get comments
submission.comments.replace_more(limit=0) # Flatten comment tree
for comment in submission.comments.list():
print(f"{comment.author}: {comment.body[:100]}")
Posting & Voting (Requires Auth)
# Submit text post
subreddit = reddit.subreddit("test")
submission = subreddit.submit(
title="Test Post",
selftext="This is the body of my post."
)
# Submit link post
submission = subreddit.submit(
title="Check this out",
url="https://example.com"
)
# Vote
submission.upvote()
submission.downvote()
submission.clear_vote()
# Comment
submission.reply("Great post!")
# Reply to comment
comment = reddit.comment(id="xyz789")
comment.reply("I agree!")
Streaming (Real-time)
# Stream new posts
for post in reddit.subreddit("python").stream.submissions():
print(f"New post: {post.title}")
# Process post...
# Stream new comments
for comment in reddit.subreddit("python").stream.comments():
print(f"New comment by {comment.author}: {comment.body[:50]}")
User Data
# Get user info
user = reddit.redditor("spez")
print(f"Karma: {user.link_karma + user.comment_karma}")
# User's posts
for post in user.submissions.new(limit=5):
print(post.title)
# User's comments
for comment in user.comments.new(limit=5):
print(comment.body[:100])
TypeScript / Node.js: Snoowrap
Installation
npm install snoowrap
# or
pnpm add snoowrap
Setup
import Snoowrap from "snoowrap";
const reddit = new Snoowrap({
userAgent: "YourApp/1.0 by YourUsername",
clientId: process.env.REDDIT_CLIENT_ID!,
clientSecret: process.env.REDDIT_CLIENT_SECRET!,
username: process.env.REDDIT_USERNAME!,
password: process.env.REDDIT_PASSWORD!,
});
// Configure rate limiting
reddit.config({
requestDelay: 1000, // 1 second between requests
continueAfterRatelimitError: true,
});
Common Operations
// Get hot posts from subreddit
const posts = await reddit.getSubreddit("typescript").getHot({ limit: 10 });
posts.forEach((post) => {
console.log(`${post.title} - ${post.score} upvotes`);
});
// Search posts
const results = await reddit.getSubreddit("programming").search({
query: "typescript",
sort: "relevance",
time: "month",
limit: 10,
});
// Get specific post
const submission = await reddit.getSubmission("abc123").fetch();
console.log(submission.title);
// Get comments
const comments = await submission.comments.fetchAll();
comments.forEach((comment) => {
console.log(`${comment.author.name}: ${comment.body.slice(0, 100)}`);
});
Posting
// Submit text post
const post = await reddit.getSubreddit("test").submitSelfpost({
title: "Test Post",
text: "This is the body.",
});
// Submit link
const linkPost = await reddit.getSubreddit("test").submitLink({
title: "Check this out",
url: "https://example.com",
});
// Vote and comment
await post.upvote();
await post.reply("Great post!");
Direct API (No Library)
Python with httpx
import httpx
import base64
from pydantic import BaseModel
class RedditClient:
def __init__(self, client_id: str, client_secret: str, user_agent: str):
self.client_id = client_id
self.client_secret = client_secret
self.user_agent = user_agent
self.access_token: str | None = None
self.client = httpx.AsyncClient()
async def authenticate(self) -> None:
"""Get application-only OAuth token."""
auth = base64.b64encode(
f"{self.client_id}:{self.client_secret}".encode()
).decode()
response = await self.client.post(
"https://www.reddit.com/api/v1/access_token",
headers={
"Authorization": f"Basic {auth}",
"User-Agent": self.user_agent,
},
data={
"grant_type": "client_credentials",
},
)
response.raise_for_status()
self.access_token = response.json()["access_token"]
async def get_posts(self, subreddit: str, sort: str = "hot", limit: int = 10) -> list[dict]:
"""Get posts from a subreddit."""
if not self.access_token:
await self.authenticate()
response = await self.client.get(
f"https://oauth.reddit.com/r/{subreddit}/{sort}",
headers={
"Authorization": f"Bearer {self.access_token}",
"User-Agent": self.user_agent,
},
params={"limit": limit},
)
response.raise_for_status()
return [post["data"] for post in response.json()["data"]["children"]]
async def close(self) -> None:
await self.client.aclose()
# Usage
async def main():
client = RedditClient(
client_id="your_id",
client_secret="your_secret",
user_agent="YourApp/1.0",
)
try:
posts = await client.get_posts("python", limit=5)
for post in posts:
print(f"{post['title']} - {post['score']} upvotes")
finally:
await client.close()
TypeScript with fetch
interface RedditPost {
title: string;
score: number;
url: string;
selftext: string;
author: string;
created_utc: number;
}
class RedditClient {
private accessToken: string | null = null;
constructor(
private clientId: string,
private clientSecret: string,
private userAgent: string
) {}
async authenticate(): Promise<void> {
const auth = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString("base64");
const response = await fetch("https://www.reddit.com/api/v1/access_token", {
method: "POST",
headers: {
Authorization: `Basic ${auth}`,
"User-Agent": this.userAgent,
"Content-Type": "application/x-www-form-urlencoded",
},
body: "grant_type=client_credentials",
});
const data = await response.json();
this.accessToken = data.access_token;
}
async getPosts(subreddit: string, sort = "hot", limit = 10): Promise<RedditPost[]> {
if (!this.accessToken) await this.authenticate();
const response = await fetch(
`https://oauth.reddit.com/r/${subreddit}/${sort}?limit=${limit}`,
{
headers: {
Authorization: `Bearer ${this.accessToken}`,
"User-Agent": this.userAgent,
},
}
);
const data = await response.json();
return data.data.children.map((child: any) => child.data);
}
}
OAuth2 Web Flow (User Authorization)
For apps where users log in with their Reddit account:
from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse
import httpx
import secrets
app = FastAPI()
state_store: dict[str, bool] = {}
REDDIT_CLIENT_ID = "your_client_id"
REDDIT_CLIENT_SECRET = "your_client_secret"
REDIRECT_URI = "http://localhost:8000/callback"
@app.get("/login")
async def login():
state = secrets.token_urlsafe(16)
state_store[state] = True
auth_url = (
f"https://www.reddit.com/api/v1/authorize"
f"?client_id={REDDIT_CLIENT_ID}"
f"&response_type=code"
f"&state={state}"
f"&redirect_uri={REDIRECT_URI}"
f"&duration=permanent"
f"&scope=identity read submit vote"
)
return RedirectResponse(auth_url)
@app.get("/callback")
async def callback(code: str, state: str):
if state not in state_store:
return {"error": "Invalid state"}
del state_store[state]
# Exchange code for token
async with httpx.AsyncClient() as client:
response = await client.post(
"https://www.reddit.com/api/v1/access_token",
auth=(REDDIT_CLIENT_ID, REDDIT_CLIENT_SECRET),
data={
"grant_type": "authorization_code",
"code": code,
"redirect_uri": REDIRECT_URI,
},
headers={"User-Agent": "YourApp/1.0"},
)
tokens = response.json()
# Store tokens securely, associate with user session
return {"access_token": tokens["access_token"][:10] + "..."}
Available Scopes
| Scope | Description |
|---|---|
identity | Access username and signup date |
read | Access posts and comments |
submit | Submit links and comments |
vote | Upvote/downvote content |
edit | Edit posts and comments |
history | Access voting history |
subscribe | Manage subreddit subscriptions |
mysubreddits | Access subscribed subreddits |
privatemessages | Access private messages |
save | Save/unsave content |
Full list: https://www.reddit.com/api/v1/scopes
Project Structure
project/
├── src/
│ ├── reddit/
│ │ ├── __init__.py
│ │ ├── client.py # Reddit client wrapper
│ │ ├── models.py # Pydantic models for posts/comments
│ │ └── scraper.py # Data collection logic
│ └── main.py
├── .env
└── pyproject.toml
Pydantic Models
from pydantic import BaseModel
from datetime import datetime
class RedditPost(BaseModel):
id: str
title: str
author: str
subreddit: str
score: int
upvote_ratio: float
url: str
selftext: str
created_utc: datetime
num_comments: int
is_self: bool
@classmethod
def from_praw(cls, submission) -> "RedditPost":
return cls(
id=submission.id,
title=submission.title,
author=str(submission.author),
subreddit=submission.subreddit.display_name,
score=submission.score,
upvote_ratio=submission.upvote_ratio,
url=submission.url,
selftext=submission.selftext,
created_utc=datetime.fromtimestamp(submission.created_utc),
num_comments=submission.num_comments,
is_self=submission.is_self,
)
class RedditComment(BaseModel):
id: str
author: str
body: str
score: int
created_utc: datetime
parent_id: str
is_submitter: bool
Anti-Patterns
- No User-Agent - Reddit blocks requests without proper User-Agent
- Ignoring rate limits - Respect 100 QPM, check
X-Ratelimit-*headers - Storing credentials in code - Use environment variables
- Not handling
MoreComments- Usereplace_more()in PRAW - Polling instead of streaming - Use
.streamfor real-time data - No error handling - Handle 429 (rate limit), 403 (forbidden), 404 (not found)
Quick Reference
# PRAW installation
pip install praw
# Snoowrap installation
npm install snoowrap
# Test authentication
python -c "import praw; r = praw.Reddit(...); print(r.user.me())"
Endpoints
| Operation | Endpoint |
|---|---|
| Auth token | POST https://www.reddit.com/api/v1/access_token |
| API requests | https://oauth.reddit.com/... |
| Subreddit posts | GET /r/{subreddit}/{sort} |
| Submission | GET /comments/{id} |
| User info | GET /user/{username}/about |
| Submit post | POST /api/submit |
| Vote | POST /api/vote |
Reviews
No reviews yet. Be the first.
Related
Frontend Slides
Create beautiful slides on the web using Claude's frontend skills
React Doctor
Your agent writes bad React. This catches it
orchestration-patterns
>
mh install skills/reddit-api