~ / guides / How to Scrape Reddit Search Results

How to Scrape Reddit Search Results

BS
Ben Shaw
Reddit data engineer · about the author
the short version
  • A Reddit search returns a ranked list of posts (and sometimes comments or whole subreddits) that match your query, either across all of Reddit or inside one community. Scraping it means running the query and collecting that result list on a schedule.
  • The public search.json shortcut returns an HTTP 403 from a datacenter IP, the same block the rest of Reddit's unauthenticated surface throws. So the working routes are the official API or a managed one.
  • The official route is PRAW: reddit.subreddit("all").search(query, sort=..., time_filter=...) for a site-wide search, or subreddit.search(query) to restrict it to one community, iterating the results.
  • A managed search endpoint returns the ranked list as JSON with no app registration. I tested it in June 2026. One honest catch: that surface is RSS-backed, so it gives you identity, title, author, and permalink, but score and num_comments come back null.

I wanted a standing list of every Reddit thread that mentioned a product name, refreshed daily, so I could see complaints and questions as they landed. That is a search-scraping job, not a subreddit-scraping one. You run a query, Reddit hands back a ranked list of matching posts, and you collect that list on a schedule. It sounds like the simplest of the Reddit scraping tasks, and the query part is. The part that trips people up is that the obvious public route is shut.

This guide on how to scrape Reddit search results covers the whole path: what a search actually returns, why the public search.json view answers with a 403, the official PRAW route for both a site-wide search and a single-community one, and a managed API that skips the credentials. I tested each of these in June 2026, and I will be honest about where each one stops.

What does a Reddit search actually return?

A Reddit search returns a ranked list of items that match your query, scored by Reddit’s relevance algorithm rather than in chronological order. Most of those items are posts, but a search can also surface matching comments and even whole subreddits whose name or description fits the query. Each result carries an identity, a title, an author, the subreddit it lives in, a permalink, and a created timestamp.

Two knobs shape that list. The first is scope: a search can run across all of Reddit, or it can be restricted to a single community so you only see results from, say, r/python. The second is ordering: Reddit lets you sort by relevance, hot, top, new, or comments, and narrow the window with a time filter of hour, day, week, month, year, or all. Sorting by new turns a search into a recency feed for monitoring, while sorting by top with a time filter gives you the highest-voted matches in a window.

When I ran a site-wide search for data science sorted by top over the past week in June 2026, the first three results were not posts at all, they were subreddits (r/datascience, r/DataScienceJobs, r/DataScienceProjects) whose names matched the query, followed by the actual post results. That mix is normal. A scraper that assumes every result is a post will choke on the subreddit rows, so the result type is a field worth reading, not ignoring.

Why does the public Reddit search URL return a 403?

The public search URL returns a 403 because it sits behind the same datacenter-IP block as the rest of Reddit’s unauthenticated surface. Reddit exposes a JSON-shaped search view at https://www.reddit.com/search.json?q=<query>, and on paper it looks like a free API. From a real datacenter IP it is not. The edge refuses the request before any results are serialized.

This is the identical wall I documented hitting on subreddit and comment endpoints, where a datacenter IP gets a 403 HTML page served by snooserv (Reddit’s web edge) no matter which User-Agent you send. I walk through the test matrix in my guide on how to scrape Reddit without getting blocked. The search route is no different: the block is tied to the IP and the request fingerprint, so dressing up the User-Agent does nothing.

There is a second, quieter failure mode worth naming. Even when an unauthenticated request slips through, Reddit can serve a stripped response with a fraction of the results you expected, so the scraper reports success while half the ranked list is missing. Detection is hard because no error is raised. The two routes that avoid both the 403 and the silent truncation are the official OAuth API and a managed scraper API, and the rest of this guide is about those.

How do you scrape Reddit search results with Python and PRAW?

You scrape Reddit search results with Python by authenticating through the official API and calling the search method on a subreddit object, and PRAW (the Python Reddit API Wrapper) is the standard way to do it. PRAW handles the OAuth token and the pagination, so the search code stays a few lines.

First, register a script app at https://www.reddit.com/prefs/apps to get a client_id and client_secret. A read-only instance needs those plus a descriptive user agent. The trick for a site-wide search is PRAW’s special all subreddit, which searches across communities instead of one:

import praw

reddit = praw.Reddit(
    client_id="YOUR_ID",
    client_secret="YOUR_SECRET",
    user_agent="reddit-search-scraper/1.0 by u/yourname",
)

# Search ALL of Reddit for a keyword, ranked by relevance.
for post in reddit.subreddit("all").search(
    "your brand name",
    sort="relevance",
    time_filter="all",
    limit=25,
):
    print(post.score, post.subreddit, "-", post.title)

Each item the loop yields is a full submission object, so you get the real post.score (net upvotes), post.num_comments, post.subreddit, post.author, post.created_utc, and post.permalink. The sort and time_filter arguments map straight to the knobs from earlier. The PRAW Subreddit reference documents the accepted values: sort is one of relevance, hot, top, new, or comments, and time_filter is one of hour, day, week, month, year, or all.

To restrict the search to a single community, swap "all" for the subreddit name. Everything else is identical:

# Same search, scoped to one subreddit.
for post in reddit.subreddit("python").search("web scraping", sort="new", limit=25):
    print(post.score, post.created_utc, "-", post.title)

The catch with PRAW is the one that applies to the whole official API, not just search: it is rate limited and gated. Reddit’s free tier allows 100 queries per minute per client averaged over a 10-minute window, and as of 2025 every app, including personal and academic ones, needs pre-approval before it can authenticate. For one keyword refreshed a few times a day that ceiling is invisible. For dozens of keywords across many communities on a tight schedule, you start counting calls, and the question becomes how to get the same ranked list without the credentials.

How do you scrape Reddit search results without the official API?

You scrape Reddit search results without the official API by sending the query to a managed scraper API that returns the ranked result list as JSON, which sidesteps both the OAuth registration and the 403 you hit on the public search.json route. In my June 2026 testing, a single GET against ChocoData’s Reddit search endpoint returned the ranked results with no app to register and no proxy pool to run. ChocoData is a third-party scraping service, unrelated to Reddit.

The request is a plain GET with the query, an optional subreddit to scope it, the sort, and your api key:

curl "https://api.chocodata.com/api/v1/reddit/search?q=web%20scraping&subreddit=python&sort=relevance&limit=25&api_key=YOUR_CHOCO_API_KEY"

The Python version returns a results array, one object per ranked hit, already in position order:

import requests

resp = requests.get(
    "https://api.chocodata.com/api/v1/reddit/search",
    params={
        "q": "web scraping",
        "subreddit": "python",     # omit this key to search all of Reddit
        "sort": "relevance",        # relevance | hot | top | new | comments
        "limit": 25,                # RSS surface caps at 25
        "api_key": "YOUR_CHOCO_API_KEY",
    },
    timeout=30,
)
data = resp.json()

print(data["total_results"], "results")
for r in data["results"]:
    print(r["position"], r["result_type"], "-", r["title"])

When I ran that against r/python for web scraping in June 2026, it returned 25 results in rank order, each with position, id, result_type (post, comment, or subreddit), title, author, author_url, subreddit, permalink, external_url, and created. You can add a t parameter (hour, day, week, month, year, or all) to set the time window, and omit subreddit entirely to run the search across all of Reddit. The proxy rotation and the anti-bot handling happen on the server side, and each call costs a fixed number of credits.

Here is the honest limitation, and the reason I tested it before recommending it. That search surface is RSS-backed, so score and num_comments come back as null on every result, not as vote counts, and the response says so itself in an _rss_limitations field. You get reliable identity, title, author, permalink, and timestamp, which is everything a keyword or brand-mention monitor needs to find and link the threads. If your workflow ranks results by score, that has to come from the official API, or from passing each permalink the search returns to a post endpoint that does carry vote data.

Reddit search results return as JSON; the RSS surface leaves score and num_comments null.

# Site-wide brand-mention sweep: no subreddit, sorted newest first.
resp = requests.get(
    "https://api.chocodata.com/api/v1/reddit/search",
    params={"q": "your brand name", "sort": "new", "limit": 25, "api_key": "YOUR_CHOCO_API_KEY"},
    timeout=30,
)
for r in resp.json()["results"]:
    print(r["created"], r["subreddit"], "-", r["permalink"])

You can get an API key on the ChocoData sign-up page and drop it into the snippets above. This route trades the free official tier for a managed one, so it is the cheaper path only once your keyword volume or the scheduling outweighs your time. For a single occasional query, PRAW inside the free tier is fine. For brand mentions tracked across all of Reddit every hour, offloading the blocking and the credentials is usually worth it.

If you are weighing several managed options against each other, the best Reddit scrapers in 2026 roundup compares them side by side.

How do you monitor Reddit for keywords and brand mentions?

You monitor Reddit by running the same search on a schedule and diffing the results against what you have already seen, so each run surfaces only the new matching threads. Search scraping is the engine; the monitor is a loop on top of it. The pattern is the same whichever route you use underneath.

The core idea is to key on each result’s stable id (or permalink) and keep a record of the ones you have processed. A new id is a new mention to alert on. Sorting by new keeps the freshest results at the top, which means you rarely need to page deep to catch everything since the last run.

import requests, json, os

SEEN = "seen_ids.json"
seen = set(json.load(open(SEEN))) if os.path.exists(SEEN) else set()

resp = requests.get(
    "https://api.chocodata.com/api/v1/reddit/search",
    params={"q": "your brand name", "sort": "new", "limit": 25, "api_key": "YOUR_CHOCO_API_KEY"},
    timeout=30,
)
for r in resp.json()["results"]:
    if r["id"] not in seen:
        print("NEW:", r["subreddit"], r["permalink"])   # send to Slack, email, etc.
        seen.add(r["id"])

json.dump(list(seen), open(SEEN, "w"))

Run that on a cron schedule and you have a working Reddit mention monitor in under thirty lines. Two practical notes from my own runs: first, search relevance is fuzzy, so a query like a short brand name pulls in coincidental matches, and a tighter query or a post-filter on the title cuts the noise. Second, because this surface does not return scores, you cannot prioritize by upvotes inside the monitor itself; to rank the day’s mentions by traction, collect the permalinks here, then fetch the high-value ones through a route that carries vote data. For pulling the full discussion under a flagged thread, my guide on how to scrape Reddit comments covers the comment tree.

Scraping publicly visible Reddit search results is generally treated as lawful in the United States, on the same footing as scraping any other public page. The Ninth Circuit’s ruling in hiQ v. LinkedIn held that scraping public data likely does not violate the Computer Fraud and Abuse Act, and the EFF’s summary of the hiQ decision walks through the reasoning that a public site has “erected no gates” to bypass.

That is the baseline, not the whole answer. Reddit’s User Agreement restricts automated access without permission, so the terms are a contract question that sits separate from the CFAA one. Search results also point at user-generated content that can contain personal data, which carries its own obligations under regimes like the GDPR if you store it, and anything behind a login is a different matter entirely.

I work through robots.txt, the User Agreement, and the case law in is scraping Reddit legal, which is the place to settle the question before you monitor at scale.

Search is one entry point into Reddit’s data. For the full workflow across posts, subreddits, comments, and search together, the complete guide to scraping Reddit ties the endpoints into one pipeline.

FAQ

Can you scrape Reddit search results without the API?

Not the easy way. The public https://www.reddit.com/search.json?q=... view returns an HTTP 403 from a datacenter IP, the same block the rest of Reddit's unauthenticated surface throws, so a plain requests.get fails before it parses anything. The working options are the official OAuth API through PRAW, residential proxies plus your own parser, or a managed scraper API that returns the ranked result list as JSON for you.

How do I search all of Reddit by keyword in Python?

Use PRAW's special all subreddit: reddit.subreddit("all").search("your query", sort="relevance", time_filter="all", limit=25) and iterate the results. Each item is a submission with .title, .score, .subreddit, and .permalink. To restrict the search to one community, swap "all" for the subreddit name, for example reddit.subreddit("python").search("web scraping").

What sort and time options does Reddit search take?

Reddit search accepts sort = relevance, hot, top, new, or comments (relevance is the default), and a time_filter = hour, day, week, month, year, or all (all is the default). In PRAW those are the sort and time_filter arguments to .search(). The time filter only narrows to those preset windows, not to an exact date range.

Does a Reddit search return upvote scores?

It depends on the surface. The official API and PRAW return the real score and num_comments per result. The managed endpoint I tested is RSS-backed, so it returns the identity, title, author, permalink, and timestamp, but score and num_comments come back as null, not vote counts. If you need ranked-by-upvotes data, use PRAW or sort the official API by top.

Is scraping Reddit search results legal?

Scraping publicly visible Reddit search results is generally treated as lawful in the US after hiQ v. LinkedIn, which held that scraping public data likely does not violate the CFAA. Reddit's User Agreement still restricts automated access without permission, and any personal data you store carries its own obligations. I cover the detail in my guide on whether scraping Reddit is legal.

BS
Ben Shaw
I've built Reddit data pipelines for years. On redditscraperapi.com I run Reddit scraping methods against live pages and publish what actually holds up.