Reddit Integration Guide
Technology: reddit · Category: comms · Last reviewed: 2026-08-23
Source: https://tech-stack.codeamanilabs.org/guide/reddit
Insight:
Reddit is a social-listening + community-engagement channel, not a payment or auth rail. The core flow is a plain OAuth2 REST API (no SDK required) — the real constraints are operational and cultural: a mandatory descriptive User-Agent, a 100 QPM per-OAuth-client budget exposed via
X-Ratelimit-*headers, andoauth.reddit.comas the base for authed calls. Since the 2023 paid-API shift the free tier is non-commercial only (commercial use needs an approved contract), so treat Reddit as a research/engagement channel, not bulk data. For codeAmani the goal is value-first participation to learn what US users actually need — never astroturf: sockpuppets, vote manipulation, and spammy self-promotion are bannable and burn the codeAmani-Labs account.
██████╗ ███████╗██████╗ ██████╗ ██╗████████╗
██╔══██╗██╔════╝██╔══██╗██╔══██╗██║╚══██╔══╝
██████╔╝█████╗ ██║ ██║██║ ██║██║ ██║
██╔══██╗██╔══╝ ██║ ██║██║ ██║██║ ██║
██║ ██║███████╗██████╔╝██████╔╝██║ ██║
╚═╝ ╚═╝╚══════╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝
Reddit Integration Guide
Focus: Use the Reddit Data API as a market-research and community-engagement channel — listen to what users in our target subreddits actually ask for, surface threads codeAmani can genuinely answer, and grow the
codeAmani-Labsaccount as a trusted voice (not a billboard).
Overview
Reddit is a forum-of-forums: thousands of topic communities ("subreddits") where people ask real questions and complain about real problems in their own words. That makes it one of the highest-signal voice-of-customer sources on the open web — and a place to build reputation by being helpful before being promotional.
The Reddit Data API is a JSON/REST API authenticated with OAuth2. There is no required SDK — every endpoint is reachable with fetch — but snoowrap (Node) and praw (Python) wrap auth, rate limiting, and pagination for you.
The codeAmani loop is listen → analyse → engage: pull threads, cluster them with Claude into themes/pain-points that inform the roadmap, then reply with genuine value (and only sometimes a soft, rule-compliant mention).
flowchart LR
A["Register app<br/>reddit.com/prefs/apps"] -->|"client_id + secret"| B["OAuth2 token<br/>/api/v1/access_token"]
B -->|"bearer token"| C["oauth.reddit.com"]
C -->|"GET /r/sub/new · /search"| D["Listen: threads + comments"]
D --> E["Analyse with Claude<br/>themes · sentiment · pain-points"]
E --> F["Roadmap / product decisions"]
C -->|"POST /api/comment · /api/submit"| G["Engage as codeAmani-Labs"]
E -.->|"value-first reply"| G
Official Documentation
| Resource | URL |
|---|---|
| API reference | https://www.reddit.com/dev/api |
| Data API Wiki (current rules, rate limits, access tiers) | https://support.reddithelp.com/hc/en-us/articles/16160319875092-Reddit-Data-API-Wiki |
| OAuth2 flow (legacy archive wiki) | https://github.com/reddit-archive/reddit/wiki/OAuth2 |
| API access rules / User-Agent (legacy archive wiki) | https://github.com/reddit-archive/reddit/wiki/API |
| Register an app | https://www.reddit.com/prefs/apps |
| snoowrap (Node wrapper — deprecated) | https://github.com/not-an-aardvark/snoowrap |
| PRAW (Python wrapper) | https://praw.readthedocs.io/ |
Heads-up on the archive wiki:
reddit-archive/…/wiki/APIstill states the old 60 req/min figure. The current, authoritative rate limit is 100 QPM per OAuth client — always cross-check the Data API Wiki above for live rules.
1. Register an app
At https://www.reddit.com/prefs/apps (logged in as codeAmani-Labs), create an app. The type decides the OAuth flow:
| App type | Use it for | Grant |
|---|---|---|
| script | Server-side bot acting as one account (our brand account) | password |
| web app | Acting as other users via OAuth consent; long-lived bots | authorization_code (+ refresh token) |
| installed app | Public clients (mobile/SPA), no secret | installed_client |
You receive a client ID (under the app name) and a client secret. Store both server-side only.
# .env.local — never commit, never ship to the browser
REDDIT_CLIENT_ID=...
REDDIT_CLIENT_SECRET=...
REDDIT_USERNAME=codeAmani-Labs
REDDIT_PASSWORD=... # only for the script-app password grant
# Descriptive User-Agent is MANDATORY — generic ones get throttled/blocked.
REDDIT_USER_AGENT="web:com.codeamanilabs.listener:v1.0 (by /u/codeAmani-Labs)"
User-Agent format (from the API rules):
<platform>:<app ID>:<version> (by /u/<username>). Reddit aggressively rate-limits or blocks default library agents (axios/x.y,python-requests). Always send a unique, descriptive UA.
2. Get an OAuth2 token
The token endpoint is POST https://www.reddit.com/api/v1/access_token, authenticated with HTTP Basic (client_id:client_secret). Tokens last ~1 hour — cache and refresh before expiry.
Read-only "listening" token (application-only)
Best for the listen/analyse half of the loop — no account actions, just reads.
// lib/reddit-auth.ts
const TOKEN_URL = "https://www.reddit.com/api/v1/access_token";
export async function getAppToken(): Promise<string> {
const basic = Buffer.from(
`${process.env.REDDIT_CLIENT_ID}:${process.env.REDDIT_CLIENT_SECRET}`
).toString("base64");
const res = await fetch(TOKEN_URL, {
method: "POST",
headers: {
Authorization: `Basic ${basic}`,
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": process.env.REDDIT_USER_AGENT!,
},
// Confidential clients (script / web app) use client_credentials.
// Public "installed" apps use grant_type=https://oauth.reddit.com/grants/installed_client&device_id=...
body: new URLSearchParams({ grant_type: "client_credentials" }),
});
if (!res.ok) throw new Error(`Reddit token failed: ${res.status}`);
const { access_token } = (await res.json()) as { access_token: string };
return access_token;
}
Posting token (script app, password grant)
Use this to act as codeAmani-Labs (comment / submit). The password grant only works for the developer account that owns a script-type app.
// Swap the body for the password grant; everything else is identical.
body: new URLSearchParams({
grant_type: "password",
username: process.env.REDDIT_USERNAME!,
password: process.env.REDDIT_PASSWORD!,
}),
For a robust long-running bot prefer a web app +
authorization_codeflow withduration=permanentto obtain a refresh token, so you never store the account password. The password grant is the quickest path for a single brand account.
3. Authenticated requests → oauth.reddit.com
Once you hold a token, all API calls go to https://oauth.reddit.com (not www.reddit.com), with a bearer token and your UA. Modhashes are not needed under OAuth.
// lib/reddit.ts
const API = "https://oauth.reddit.com";
async function redditGet(path: string, token: string) {
const res = await fetch(`${API}${path}`, {
headers: {
Authorization: `bearer ${token}`,
"User-Agent": process.env.REDDIT_USER_AGENT!,
},
});
// Respect the budget — see §5.
logRateLimit(res.headers);
if (!res.ok) throw new Error(`Reddit GET ${path} → ${res.status}`);
return res.json();
}
Listen: newest posts in a subreddit
// GET /r/:subreddit/new — limit ≤ 100, paginate with `after`
const data = await redditGet("/r/SaaS/new?limit=50", token);
const posts = data.data.children.map((c: any) => ({
fullname: c.data.name, // e.g. "t3_abc123" — the post's fullname
title: c.data.title,
body: c.data.selftext,
url: `https://reddit.com${c.data.permalink}`,
score: c.data.score,
numComments: c.data.num_comments,
}));
Listen: search for threads we can answer
// Search ALL of Reddit
await redditGet(`/search?q=${encodeURIComponent("m-pesa integration nextjs")}&sort=new&limit=25`, token);
// Search WITHIN one subreddit (restrict_sr=true)
await redditGet(`/r/Kenya/search?q=mpesa+api&restrict_sr=true&sort=relevance&limit=25`, token);
// Find relevant communities to monitor
await redditGet(`/subreddits/search?q=saas&sort=relevance&limit=10`, token);
Engage: comment on a thread
thing_id is the fullname of the parent (t3_ = post, t1_ = comment). Requires the submit scope and a posting token.
async function redditPost(path: string, token: string, form: Record<string, string>) {
const res = await fetch(`https://oauth.reddit.com${path}`, {
method: "POST",
headers: {
Authorization: `bearer ${token}`,
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": process.env.REDDIT_USER_AGENT!,
},
body: new URLSearchParams(form),
});
if (!res.ok) throw new Error(`Reddit POST ${path} → ${res.status}`);
return res.json();
}
// Reply to a post
await redditPost("/api/comment", token, {
api_type: "json",
thing_id: "t3_abc123",
text: "Here's how we solved the STK Push idempotency problem…", // raw markdown
});
Engage: submit a self-post
// kind=self for a text post; kind=link with `url` for a link post.
await redditPost("/api/submit", token, {
api_type: "json",
sr: "kenya",
kind: "self",
title: "We open-sourced a Daraja M-Pesa helper for Next.js",
text: "After shipping a few M-Pesa flows, here's what we learned…",
});
Pre-validate before submitting.
GET /api/v1/{subreddit}/post_requirementsreturns mod rules (min/max title length, required flair, blacklisted words, allowed domains). Check it first to avoid auto-removals — and to respect the community.
4. snoowrap quickstart (Node)
A wrapper can hand-roll less auth + pagination. snoowrap handles tokens, the
rate-limit budget, and listings.
⚠️ snoowrap is deprecated. The npm package (
snoowrap@1.23.0, last real release ~2020) is now flagged "no longer supported" and its bundled types track Reddit's older OAuth response shapes — the compiler will confidently lie as the API drifts. For new codeAmani code prefer the plain-fetchpath in §2–§3 (one bearer token, your own types); reach for snoowrap only for a quick throwaway script.
npm install snoowrap # deprecated — see the warning above
import Snoowrap from "snoowrap";
const r = new Snoowrap({
userAgent: process.env.REDDIT_USER_AGENT!,
clientId: process.env.REDDIT_CLIENT_ID!,
clientSecret: process.env.REDDIT_CLIENT_SECRET!,
username: process.env.REDDIT_USERNAME!,
password: process.env.REDDIT_PASSWORD!,
});
// Listen
const newPosts = await r.getSubreddit("SaaS").getNew({ limit: 50 });
const hits = await r.search({ query: "mpesa api", sort: "new", time: "week" });
// Engage
await r.getSubmission("abc123").reply("Genuinely useful answer here…");
snoowrapis unmaintained (see the warning above), so on Node the plain-fetchpath ages better. For pure data-collection / analysis pipelines, PRAW is the actively-maintained Python option and pairs naturally with pandas/Claude for theme clustering. PRAW is now on the 8.x line (pip install praw→praw==8.0.3, requires Python 3.10+); the 8.0 major dropped Python 3.8/3.9, made most listing/submit arguments keyword-only, and mergedsubmit_image/submit_video/submit_galleryinto a singlesubmit().
5. Rate limits & resilience
OAuth clients get 100 queries/minute (QPM) per OAuth client ID, averaged over a rolling 10-minute window (so short bursts are fine). Unauthenticated / non-OAuth traffic is capped at 10 QPM and is effectively blocked for anything real — always send OAuth. (The old 60/min number you'll still see on the archived wiki predates the 2023 API changes; ignore it.) Every response carries the live budget — read it and back off rather than hammering:
function logRateLimit(h: Headers) {
const remaining = Number(h.get("x-ratelimit-remaining") ?? "100");
const reset = Number(h.get("x-ratelimit-reset") ?? "0"); // seconds until window reset
if (remaining < 5) {
// Sleep until the window resets instead of risking a 429.
console.warn(`Reddit budget low: ${remaining} left, reset in ${reset}s`);
}
}
| Header | Meaning |
|---|---|
X-Ratelimit-Used |
Requests used this window |
X-Ratelimit-Remaining |
Requests left this window |
X-Ratelimit-Reset |
Seconds until the window resets |
On 429, honour X-Ratelimit-Reset (or Retry-After) and retry with backoff. Cache tokens (~1 h) and listing results — listening doesn't need to be real-time.
Access tiers & pricing (post-2023)
Since Reddit's 2023 API changes the Data API is tiered — the guide's default use (voice-of-customer research on one brand account) sits comfortably in the free tier, but know where the line is:
| Tier | Who | Limit / cost |
|---|---|---|
| Free | Personal projects, bots, mod tools, non-commercial/academic research | Self-serve, ≤100 QPM per OAuth client, no commercial use |
| Commercial / enterprise | Ad-supported apps, paywalled or monetized products, bulk data | Approved contract required (manual review, ~weeks); Reddit's published enterprise rate is ~$0.24 per 1,000 API calls |
- Don't scrape at scale or resell Reddit content — that's the commercial line and needs approval. Store only what the research needs (see the Data API Terms).
codeAmani notes
Security
- All credentials (
client_id,client_secret, account password / refresh token) live server-side only — in.env.local/ Vercel env vars, never in a client bundle or aNEXT_PUBLIC_*var. Do Reddit calls from API routes or background jobs. - Never log tokens or passwords. Treat the refresh token like a password.
Culture & ToS — this is the part that matters most
- The brief is to "promote without explicitly saying so." On Reddit that means be genuinely helpful first; a relevant link is welcome only when it actually answers the question. Overt marketing, repeated drops of the same link, and thin self-promo get removed and can ban the account.
- No sockpuppets, no vote manipulation, no astroturfing — all are site-wide-rule violations and the fastest way to lose the
codeAmani-Labsaccount. One authentic account, real participation. - Respect each subreddit's self-promotion rules and Reddiquette (a common norm: keep self-promotion well under ~10% of your activity). Read the sidebar/rules before posting; use
post_requirementsto pre-check. - The Reddit Data API Terms govern commercial and bulk use — register your app, stay within rate limits, and store only the data you need. Don't redistribute scraped user content.
AI routing (ties to the AI Routing Policy)
- Pipe collected titles/bodies/comments into Claude for sentiment, theme clustering, and pain-point extraction — turn raw threads into a ranked list of "what users keep asking for." Use OpenAI structured output if you want strict JSON tags per thread. This is the bridge from listening to roadmap.
Market fit (US-first, Kenya per-project)
- codeAmani is US-first, so default monitoring to US-relevant communities — e.g.
r/SaaS,r/smallbusiness,r/Entrepreneur,r/webdev— to learn what US consumers/SMBs want from AI tooling. - For Kenya-targeted projects, monitor
r/Kenya,r/Nairobi, and fintech/dev threads to validate M-Pesa / low-bandwidth assumptions straight from users.
Official docs:
- https://www.reddit.com/dev/api
- https://support.reddithelp.com/hc/en-us/articles/16160319875092-Reddit-Data-API-Wiki
- https://github.com/reddit-archive/reddit/wiki/OAuth2
- https://github.com/reddit-archive/reddit/wiki/API
- https://www.reddit.com/prefs/apps
- https://github.com/not-an-aardvark/snoowrap
- https://praw.readthedocs.io/