Automate Reddit comment replies by polling new comments via GET /r/{subreddit}/comments, matching keyword rules, then posting responses with POST /api/comment using the thing_id of the parent comment. Requires OAuth2 with submit scope. Key limit: 60 RPM with OAuth. Critical gotcha: Reddit returns RATELIMIT errors inside 200 OK responses — you must parse the JSON body for errors, not just check HTTP status.
API Quick Reference
OAuth 2.0
60 requests/minute
JSON
Available
Understanding the Reddit API
The Reddit Data API is a REST API that gives programmatic access to Reddit's content, communities, and moderation tools. It uses OAuth2 for authentication and returns JSON responses. All authenticated requests must go to oauth.reddit.com, not www.reddit.com — using the wrong base URL drops you to the unauthenticated 10 RPM limit.
For comment automation, the core workflow is: authenticate to get an access token, poll for new comments in target subreddits, evaluate each comment against your rules, and reply using POST /api/comment. The API uses fullname identifiers (like t1_abc123 for comments, t3_abc123 for posts) as references throughout.
The free tier supports 60 requests per minute with OAuth2, which is sufficient for monitoring dozens of subreddits and responding to matching comments. Commercial use beyond this requires an enterprise agreement at $12,000/month, but personal bots and community tools remain free indefinitely per Reddit's 2023 policy.
https://oauth.reddit.comSetting Up Reddit API Authentication
Reddit uses OAuth2 with multiple grant types. For a personal bot or script, use the password grant (script-type app) which lets you authenticate directly with your credentials without a browser redirect. For multi-user applications, use the authorization_code flow. Access tokens expire after 1 hour and must be refreshed.
- 1Go to reddit.com/prefs/apps and click 'create another app' at the bottom
- 2Select 'script' as the app type (for personal bots) or 'web app' for multi-user apps
- 3Set the redirect URI to http://localhost:8080 for script apps
- 4Save and note your client_id (shown below the app name) and client_secret
- 5Request token via POST to https://www.reddit.com/api/v1/access_token with Basic auth (client_id:client_secret)
- 6Include grant_type=password, username, and password in the request body
- 7Set your User-Agent header: <platform>:<app-id>:<version> (by /u/<your_username>)
- 8Use the returned access_token in all subsequent API calls as: Authorization: Bearer <token>
1import requests2import base6434CLIENT_ID = 'your_client_id'5CLIENT_SECRET = 'your_client_secret'6USERNAME = 'your_reddit_username'7PASSWORD = 'your_reddit_password'8USER_AGENT = 'python:com.example.mybot:v1.0.0 (by /u/your_reddit_username)'910def get_access_token():11 auth = requests.auth.HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET)12 data = {13 'grant_type': 'password',14 'username': USERNAME,15 'password': PASSWORD16 }17 headers = {'User-Agent': USER_AGENT}18 response = requests.post(19 'https://www.reddit.com/api/v1/access_token',20 auth=auth,21 data=data,22 headers=headers23 )24 response.raise_for_status()25 return response.json()['access_token']2627token = get_access_token()28print(f'Token acquired: {token[:20]}...')Security notes
- •Store CLIENT_ID, CLIENT_SECRET, USERNAME, and PASSWORD in environment variables — never hardcode them
- •The User-Agent header must follow the exact format <platform>:<app-id>:<version> (by /u/<username>) or Reddit aggressively rate-limits you
- •Access tokens expire after 1 hour — implement automatic refresh before expiry
- •Use a dedicated Reddit account for your bot, separate from your personal account
- •Script-type apps expose your credentials directly — never deploy this pattern in client-side code
Key endpoints
/r/{subreddit}/commentsFetches the latest comments across a subreddit. Use limit=100 to get the maximum per request. Supports before/after pagination with comment fullnames.
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | number | optional | Number of comments to return, max 100 |
before | string | optional | Return comments before this fullname (for pagination) |
after | string | optional | Return comments after this fullname |
sort | string | optional | Sort order: new, hot, top, controversial |
Response
1{"kind": "Listing", "data": {"after": "t1_xyz789", "children": [{"kind": "t1", "data": {"id": "abc123", "name": "t1_abc123", "author": "user1", "body": "Has anyone tried the new feature?", "subreddit": "programming", "created_utc": 1714500000}}]}}/api/commentPosts a reply to a comment or post. The thing_id is the fullname of the item you're replying to (t1_ prefix for comments, t3_ for posts). Requires the submit scope.
| Parameter | Type | Required | Description |
|---|---|---|---|
thing_id | string | required | Fullname of the parent (t1_xxx for comment, t3_xxx for post) |
text | string | required | Markdown text of the reply |
return_rtjson | boolean | optional | If true, returns rich text JSON |
Request
1{"thing_id": "t1_abc123", "text": "Thanks for asking! Here's the answer..."}Response
1{"json": {"errors": [], "data": {"things": [{"kind": "t1", "data": {"id": "def456", "name": "t1_def456", "author": "mybot", "body": "Thanks for asking!"}}]}}}/r/{subreddit}/newReturns the newest posts in a subreddit. Use this to find recent posts to monitor for comments, or to reply to new posts matching your criteria.
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | number | optional | Number of posts to return, max 100 |
after | string | optional | Pagination cursor (post fullname) |
Response
1{"kind": "Listing", "data": {"children": [{"kind": "t3", "data": {"id": "post123", "name": "t3_post123", "title": "Question about API integration", "selftext": "I'm trying to connect...", "author": "poster1", "created_utc": 1714500000}}]}}Step-by-step automation
Authenticate and Get Access Token
Why: All Reddit API calls to oauth.reddit.com require a valid Bearer token — without it, you're limited to 10 RPM as an anonymous caller.
Use the password grant (script-type app) to exchange your bot credentials for an access token. The token lasts 1 hour, so build refresh logic into your bot loop. Always include the User-Agent header — Reddit tracks this and throttles bots with missing or invalid User-Agents.
1curl -X POST https://www.reddit.com/api/v1/access_token \2 -u 'YOUR_CLIENT_ID:YOUR_CLIENT_SECRET' \3 -H 'User-Agent: script:com.example.bot:v1.0 (by /u/yourusername)' \4 -d 'grant_type=password&username=YOUR_USERNAME&password=YOUR_PASSWORD'Pro tip: Store the token expiry time (Date.now() + 3600000) and check before each API call. Refresh proactively at 50 minutes to avoid mid-run expiry.
Expected result: A JSON response with access_token, token_type: bearer, expires_in: 3600, and scope fields.
Poll for New Comments in Target Subreddits
Why: Reddit has no webhook for new comments — you must poll the listing endpoint and track which comments you've already processed using their fullnames.
Call GET /r/{subreddit}/comments with limit=100 and sort=new to get the latest comments. Store the fullname of the newest comment as your cursor. On subsequent polls, use the before parameter (or track by created_utc) to only process new comments. Design for 60 RPM total — if monitoring 10 subreddits, you can poll each every 10 seconds.
1curl -X GET 'https://oauth.reddit.com/r/python/comments?limit=100&sort=new' \2 -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \3 -H 'User-Agent: script:com.example.bot:v1.0 (by /u/yourusername)'Pro tip: Track processed comment IDs in a local set or Redis to avoid replying twice. Clear the set periodically (comments older than 24h won't need replies).
Expected result: A listing of up to 100 comment objects, each with id, name (fullname), author, body, subreddit, and created_utc fields.
Filter Comments Against Keyword Rules
Why: Replying to every comment wastes quota and gets your bot flagged — only reply to comments that match your intent criteria.
Loop through the fetched comments and check each against your keyword or regex rules. Filter out comments from your own bot account, already-processed comments, and comments in locked threads. Build a simple scoring system if you have multiple trigger conditions.
1# Filtering is done client-side — no separate API call needed2# Just check the comment body field from the previous step's responsePro tip: Add a minimum account age or karma check on the comment author to avoid replying to throwaway accounts or spam. Pull user data with GET /user/{username}/about.
Expected result: A filtered list of comment objects that your bot should reply to.
Post the Reply and Handle RATELIMIT in Response Body
Why: Reddit's per-subreddit rate limiter returns errors inside 200 OK — your code must check the response JSON body, not just HTTP status.
POST to /api/comment with the thing_id (the comment's fullname like t1_abc123) and your reply text in Markdown. After posting, always check the response JSON for errors: look for json.errors array. A RATELIMIT error in this array means you're posting too fast in that subreddit — back off and retry after the specified duration. Add a minimum delay between replies (2-5 seconds) to appear human-like.
1curl -X POST https://oauth.reddit.com/api/comment \2 -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \3 -H 'User-Agent: script:com.example.bot:v1.0 (by /u/yourusername)' \4 -H 'Content-Type: application/x-www-form-urlencoded' \5 -d 'thing_id=t1_abc123&text=Thanks+for+your+question%21+Here+is+the+answer...'Pro tip: Parse the RATELIMIT error message — it tells you exactly how long to wait ('try again in 8 minutes'). Extract the number with a regex and sleep for that duration instead of a fixed backoff.
Expected result: On success, the response body contains json.errors: [] and json.data.things[0].data.id with the new comment's ID.
Complete working code
This script polls a list of subreddits for new comments matching keyword rules, posts replies to matching comments, and handles Reddit's unusual RATELIMIT-in-200-OK error pattern. It tracks processed comment IDs to avoid duplicates and refreshes the OAuth token before expiry.
1import requests2import time3import os4import logging5from datetime import datetime, timedelta67logging.basicConfig(level=logging.INFO)8log = logging.getLogger('reddit_bot')910CLIENT_ID = os.environ['REDDIT_CLIENT_ID']11CLIENT_SECRET = os.environ['REDDIT_CLIENT_SECRET']12USERNAME = os.environ['REDDIT_USERNAME']13PASSWORD = os.environ['REDDIT_PASSWORD']14USER_AGENT = f'python:com.example.replybot:v1.0 (by /u/{USERNAME})'1516SUBREDDITS = ['python', 'learnprogramming']17KEYWORDS = ['how do I connect', 'supabase question', 'api help']18REPLY_TEMPLATE = 'Great question! You might find this useful: [link]. Let me know if you need more details.'1920token = None21token_expiry = datetime.now()22processed_ids = set()2324def refresh_token_if_needed():25 global token, token_expiry26 if datetime.now() >= token_expiry - timedelta(minutes=5):27 auth = requests.auth.HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET)28 r = requests.post(29 'https://www.reddit.com/api/v1/access_token',30 auth=auth,31 data={'grant_type': 'password', 'username': USERNAME, 'password': PASSWORD},32 headers={'User-Agent': USER_AGENT}33 )34 r.raise_for_status()35 data = r.json()36 token = data['access_token']37 token_expiry = datetime.now() + timedelta(seconds=data['expires_in'])38 log.info('Token refreshed')3940def api_get(path, params=None):41 refresh_token_if_needed()42 r = requests.get(43 f'https://oauth.reddit.com{path}',44 headers={'Authorization': f'Bearer {token}', 'User-Agent': USER_AGENT},45 params=params46 )47 r.raise_for_status()48 return r.json()4950def post_reply(thing_id, text):51 refresh_token_if_needed()52 r = requests.post(53 'https://oauth.reddit.com/api/comment',54 headers={'Authorization': f'Bearer {token}', 'User-Agent': USER_AGENT},55 data={'thing_id': thing_id, 'text': text}56 )57 r.raise_for_status()58 result = r.json()59 errors = result.get('json', {}).get('errors', [])60 if errors:61 if errors[0][0] == 'RATELIMIT':62 log.warning(f'Rate limited by subreddit: {errors[0][1]}')63 time.sleep(600)64 return None65 raise Exception(f'Reply error: {errors}')66 return result['json']['data']['things'][0]['data']['id']6768def run_bot():69 log.info('Starting comment reply bot')70 while True:71 for subreddit in SUBREDDITS:72 try:73 data = api_get(f'/r/{subreddit}/comments', {'limit': 100, 'sort': 'new'})74 comments = data['data']['children']75 for item in comments:76 c = item['data']77 if c['id'] in processed_ids:78 continue79 processed_ids.add(c['id'])80 body = c.get('body', '').lower()81 if c['author'] == USERNAME:82 continue83 if any(kw.lower() in body for kw in KEYWORDS):84 log.info(f'Replying to {c["name"]} in r/{subreddit}')85 reply_id = post_reply(c['name'], REPLY_TEMPLATE)86 if reply_id:87 log.info(f'Reply posted: t1_{reply_id}')88 time.sleep(3)89 except Exception as e:90 log.error(f'Error in r/{subreddit}: {e}')91 time.sleep(30)9293if __name__ == '__main__':94 run_bot()Error handling
errors: [["RATELIMIT", "you are doing that too much. try again in 8 minutes.", "ratelimit"]]Per-subreddit spam protection triggers when you post too frequently. New accounts with low karma are especially vulnerable to this. The error is deliberately embedded in a 200 OK response to catch bots that only check HTTP status.
Parse json.errors in every /api/comment response. Extract the wait time from the error message using a regex like /try again in (\d+) minute/, then sleep for that duration before retrying.
Sleep for the specified duration (usually 5-15 minutes), then retry once. If RATELIMIT persists, add a 2x multiplier on each subsequent retry.
401 UnauthorizedAccess token expired (tokens last 1 hour) or the token was revoked.
Refresh the access token using the same password grant and retry the request with the new token.
Immediate retry after token refresh. No backoff needed.
USER_REQUIRED or SUBREDDIT_NOTALLOWEDUSER_REQUIRED means the endpoint needs a user context (app-only tokens won't work). SUBREDDIT_NOTALLOWED means the bot's account lacks karma, is too new, or has been banned from the subreddit.
Use the password grant (user context), not client_credentials. For SUBREDDIT_NOTALLOWED, the account needs to build karma organically before the subreddit allows posting.
No retry — fix the underlying auth or account issue.
Too Many RequestsGlobal rate limit exceeded (60 RPM with OAuth). This is the HTTP-level rate limit, distinct from the per-subreddit RATELIMIT that comes back as 200.
Read the X-Ratelimit-Reset header to know when the window resets. Implement request queuing to stay under 1 request per second on average.
Exponential backoff starting at 1s, doubling to max 60s. Check X-Ratelimit-Reset before retrying.
errors: [["THREAD_LOCKED", "that thread has been locked by the moderators", "thing_id"]]The post or comment thread has been locked by moderators, preventing new replies.
Check the locked field in the comment's parent post data. Skip locked threads entirely — no amount of retrying will succeed.
No retry. Skip this comment and continue processing others.
Rate Limits for Reddit API
| Scope | Limit | Window |
|---|---|---|
| Per app (with OAuth) | 60 requests | per minute |
| Per IP (without OAuth) | 10 requests | per minute |
| Per subreddit (spam protection) | Variable — returned in response body | Rolling window (minutes to hours) |
1import time2import requests34def api_request_with_backoff(method, url, max_retries=5, **kwargs):5 for attempt in range(max_retries):6 r = getattr(requests, method)(url, **kwargs)7 if r.status_code == 429:8 reset = int(r.headers.get('X-Ratelimit-Reset', 60))9 print(f'Rate limited. Waiting {reset}s')10 time.sleep(reset)11 continue12 r.raise_for_status()13 # Check for embedded RATELIMIT errors14 if r.headers.get('Content-Type', '').startswith('application/json'):15 errors = r.json().get('json', {}).get('errors', [])16 if errors and errors[0][0] == 'RATELIMIT':17 time.sleep(min(60 * (2 ** attempt), 600))18 continue19 return r20 raise Exception('Max retries exceeded')- Always use OAuth2 — unauthenticated requests drop to 10 RPM which is nearly unusable
- Monitor X-Ratelimit-Remaining in response headers and slow down when it approaches zero
- Add 1-2 second delays between consecutive comment replies to avoid triggering per-subreddit rate limiting
- Check the RATELIMIT error in response bodies — HTTP status alone is not sufficient for Reddit
- Design for 60 RPM total across all subreddits, not 60 per subreddit
Security checklist
- Store REDDIT_CLIENT_ID, REDDIT_CLIENT_SECRET, USERNAME, and PASSWORD in environment variables — never hardcode credentials
- Use a dedicated bot account separate from your personal Reddit account
- Set an accurate User-Agent following the required format: <platform>:<app-id>:<version> (by /u/<username>)
- Implement token expiry tracking and refresh before the 1-hour expiry
- Log all bot actions with timestamps and comment IDs for audit trail and debugging
- Add a kill switch or dry-run mode to the bot for testing without posting live comments
- Never store Reddit passwords in code, config files, or version control
- Review your bot's reply template to ensure it complies with subreddit rules before deployment
Automation use cases
Customer Support Bot
beginnerMonitor brand-name mentions in relevant subreddits and automatically reply with helpful resources or escalate to human support.
FAQ Bot for Your Subreddit
beginnerAuto-reply to common repeated questions in your community subreddit with pre-written answers and links to documentation.
Cross-Subreddit Trend Alert
intermediateDetect rising keywords across multiple subreddits and send alerts to Slack or email when volume spikes.
Competitor Monitoring Reply Bot
advancedMonitor mentions of competitor products and reply with factual comparisons, fully compliant with subreddit promotional rules.
No-code alternatives
Don't want to write code? These platforms can automate the same workflows visually.
Zapier
Free tier available; Starter from $19.99/monthZapier's Reddit integration can trigger on new posts (not comments) and post new submissions, but does not support comment replies natively. You'd need a multi-step Zap with a webhook to your custom endpoint.
- + Visual workflow builder
- + No coding required
- + Reliable infrastructure
- - No native comment reply trigger
- - Costs scale with task volume
- - Limited filtering logic
Make
Free tier available; Core from $9/monthMake (formerly Integromat) has a Reddit module that handles watching new posts and creating comments, with more granular filtering than Zapier.
- + More flexible than Zapier for Reddit
- + Visual flow editor
- + Handles error scenarios
- - Limited to post-level triggers, not comment-level
- - Per-operation pricing
- - No RATELIMIT body parsing
n8n
Free self-hosted; Cloud from €20/monthn8n's Reddit node supports creating posts and comments with the HTTP Request node as a fallback for advanced operations. Self-hosted option eliminates per-operation costs.
- + Self-hostable (free)
- + Full HTTP flexibility
- + Code execution nodes for custom logic
- - Requires more setup than Zapier/Make
- - Reddit node has limited operations
- - No visual RATELIMIT handling
Best practices
- Always parse the JSON body of /api/comment responses for errors — Reddit returns RATELIMIT inside 200 OK, not as HTTP 429
- Use fullnames (t1_abc123 format) as cursors for pagination instead of page offsets — they're stable across time
- Add 2-3 second delays between replies to appear human-like and reduce per-subreddit rate limit triggering
- Track processed comment IDs in a persistent store (Redis, SQLite) to survive bot restarts without re-processing
- Monitor your bot account's karma — low karma accounts get more aggressively throttled by subreddit protections
- Test in smaller, less strict subreddits before deploying to high-traffic communities
- Include a way for users to opt out ('reply STOP to unsubscribe') where appropriate to stay within Reddit's anti-spam rules
- Log rejected replies with their RATELIMIT messages to understand which subreddits have the strictest limits
Ask AI to help
Copy one of these prompts to get a personalized, working implementation.
I'm building a Reddit comment reply bot using Python and the Reddit OAuth2 API. The bot polls /r/{subreddit}/comments every 30 seconds, checks each comment body for keywords, and replies using POST /api/comment. The problem is Reddit sometimes returns RATELIMIT errors inside 200 OK responses (not as HTTP 429). Help me build a robust reply function that: 1) detects RATELIMIT in the json.errors array, 2) extracts the wait time from the error message, 3) sleeps the exact required duration and retries once, 4) raises an exception for other error types. Include proper logging.
Build a Reddit bot monitoring dashboard. It should show: a table of subreddits being monitored with their last poll time, a live feed of matched comments with their text and subreddit, a log of replies sent with timestamp, comment ID, and status (success/rate-limited/error), and a rate limit gauge showing current RPM usage vs the 60 RPM limit. Use a dark theme with green/red status indicators. Connect to a Node.js backend that runs the actual bot polling logic.
Frequently asked questions
Is the Reddit API free for comment reply bots?
Yes — personal bots, mod bots, and non-commercial tools operate free within the 60 RPM OAuth limit. Reddit explicitly guaranteed free access for mod bots in 2023. Commercial use (apps distributed to other users at scale) requires an enterprise agreement at $12,000/month for up to 50 million API calls.
Why does my POST /api/comment return 200 OK but the comment never appears?
Check the json.errors array in the response body. Reddit returns application-level errors inside 200 responses. Common causes: RATELIMIT (posting too fast), THREAD_LOCKED (thread is locked), SUBREDDIT_NOTALLOWED (account lacks karma or is banned), or ALREADY_SUB (duplicate submission).
What happens when I hit the rate limit?
You'll see two types: a global HTTP 429 (exceeded 60 RPM) with an X-Ratelimit-Reset header showing when to retry, and a per-subreddit RATELIMIT embedded in a 200 OK body (e.g., 'try again in 8 minutes'). Both require waiting before retrying. The per-subreddit limit is subreddit-specific and hits harder on new/low-karma accounts.
Can I reply to comments using an API key without OAuth?
No. Posting comments requires a user context, which means full OAuth2 authentication with a real Reddit account. The app-only client_credentials flow (no user context) only provides read access and drops your rate limit to 10 RPM. Use the password grant with a dedicated bot account.
How do I avoid my bot getting banned from subreddits?
Introduce delays between replies (2-5 seconds minimum), vary your reply text to avoid repetition, respect the per-subreddit RATELIMIT signals, disclose in your User-Agent that it's a bot, and read subreddit rules — many explicitly ban bots without moderator approval.
Can I use PRAW (Python Reddit API Wrapper) instead of raw HTTP?
Yes — PRAW is the recommended Python library for Reddit bots. It handles authentication, token refresh, rate limiting, and the RATELIMIT-in-200-body detection automatically. Install with pip install praw and use praw.Reddit() with your credentials. Raw HTTP is useful for non-Python environments or when you need fine-grained control.
Can RapidDev help build a custom Reddit bot integration?
Yes. RapidDev has built 600+ apps including community management bots and social media automation tools. We can build production-ready Reddit bots with proper rate limiting, error handling, and dashboards. Contact us for a free consultation.
Need this automated?
Our team has built 600+ apps with API automations. We can build this for you.
Book a free consultation