Illustration for "How to Search Reddit with Python"

How to Search Reddit with Python

Every example here runs as-is against the live API: one pip install, your first search, a pagination loop that doesn't drop results, and a scheduled poll for ongoing monitoring.

Setup

Sign up — no card required — for 1,000 free Reddit searches, then create a key from /developer. You only need requests:

terminal
pip install requests

Your first search

Every call sends your key as x-api-key and returns Reddit's own field names untouched, wrapped in a small envelope:

python
import requests

API_KEY = "YOUR_KEY"
BASE = "https://api.threadsnoop.com/v1"

resp = requests.get(
    f"{BASE}/posts",
    params={"subreddit": "SaaS", "q": "burnout", "limit": 25},
    headers={"x-api-key": API_KEY},
)
resp.raise_for_status()
body = resp.json()

for post in body["data"]:
    print(post["title"], post["permalink"])

q= is an exact-phrase filter (with basic plural flexing) applied server-side, so data only contains matches — no client-side filtering needed for a simple keyword search. Reads are $1.50 per 1,000 (as low as $1.00/1,000 in bulk), 1 credit per request regardless of how many results come back.

Paginating through every result

body["_threadsnoop"] carries a cursor and has_more. Pass the cursor back as after= when sorting oldest-first, or before= for the default newest-first order, and stop at has_more: false:

python
def search_all(subreddit, q, base=BASE, key=API_KEY):
    results = []
    cursor = None
    while True:
        params = {"subreddit": subreddit, "q": q, "limit": 100, "sort": "desc"}
        if cursor:
            params["before"] = cursor
        resp = requests.get(f"{base}/posts", params=params, headers={"x-api-key": key})
        resp.raise_for_status()
        body = resp.json()
        results.extend(body["data"])
        if not body["_threadsnoop"]["has_more"]:
            break
        cursor = body["_threadsnoop"]["cursor"]
    return results

Ask for limit=100 — fewer results per page just means more pages, and every page costs 1 credit regardless of size. A page with zero matches for your q= still costs 1 credit, since it's one upstream read either way; scope a rare phrase with after=/before= first rather than paginating a year of history blind.

Searching comments too

Comments outnumber posts roughly 10 to 1 on most subreddits, and the same pattern works on /v1/comments:

python
resp = requests.get(
    f"{BASE}/comments",
    params={"subreddit": "freelance", "q": "invoice", "limit": 100},
    headers={"x-api-key": API_KEY},
)
comments = resp.json()["data"]

Handling rate limits

Every key gets the same limit — 2 requests per second sustained, burst of 10 — regardless of plan. A 429 response includes a Retry-After header; respect it rather than guessing:

python
import time

def get_with_retry(url, params, headers, max_retries=3):
    for attempt in range(max_retries):
        resp = requests.get(url, params=params, headers=headers)
        if resp.status_code == 429:
            wait = int(resp.headers.get("Retry-After", 2))
            time.sleep(wait)
            continue
        resp.raise_for_status()
        return resp.json()
    raise RuntimeError("gave up after retries")

Check your balance and limit any time with GET /v1/account — it's free and doesn't cost a credit.

Monitoring a subreddit on a schedule

There's no webhook — this is a pull API — so ongoing monitoring means calling on a schedule and tracking the newest post you've already seen:

python
# cron: */30 * * * * python3 poll.py
import json, os

STATE_FILE = "last_seen.json"

def poll_new(subreddit):
    try:
        last_seen = json.load(open(STATE_FILE))["last_id"]
    except FileNotFoundError:
        last_seen = None

    resp = requests.get(
        f"{BASE}/posts",
        params={"subreddit": subreddit, "sort": "desc", "limit": 100},
        headers={"x-api-key": API_KEY},
    )
    posts = resp.json()["data"]

    new_posts = []
    for post in posts:
        if post["id"] == last_seen:
            break
        new_posts.append(post)

    if posts:
        json.dump({"last_id": posts[0]["id"]}, open(STATE_FILE, "w"))
    return new_posts

Fresh posts (under roughly 36 hours old) carry a placeholder score and comment count — score: 1, num_comments: 0 — until Reddit finalizes them. For a real comment count on something that fresh, call /v1/comments/tree with the post's id instead.

Full endpoint reference, response shapes, and the billing model in more depth: the practical API guide. Building the same thing in TypeScript instead? search Reddit with TypeScript. Want an LLM in the loop instead of writing the filtering logic yourself? using AI agents to search Reddit.

Frequently asked questions

Do I need an SDK to search Reddit with Python?

No — the requests library and an API key are enough. Every endpoint is plain REST returning Reddit's own field names, so there's no client library to learn or keep updated.

How do I avoid dropping results across pages?

Follow the cursor: each response's _threadsnoop.cursor and has_more tell you exactly where to resume. Pass the cursor back as before= (default newest-first sort) or after= (oldest-first) and stop once has_more is false, rather than guessing an offset.

How much does searching Reddit with Python cost?

1 credit per request regardless of endpoint or how many results come back — $1.50 per 1,000 reads, as low as $1.00 per 1,000 in bulk. New keys start with 1,000 free reads.

How do I monitor a subreddit continuously in Python?

There's no webhook — call on a schedule (a cron job is enough) with sort=desc, and stop once you hit the newest post ID you saw last time. Store that ID between runs so you never reprocess the same posts twice.

Start querying in the next five minutes

Sign up, grab your key, and run the first search example above. Your first 1,000 Reddit searches are already on your account.

1,000 free Reddit searches on signup, no card required.