# Reddit Scraper (`s-r/reddit-scraper`) Actor

- **URL**: https://apify.com/s-r/reddit-scraper.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Social media, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Reddit Scraper

A Reddit scraper that returns posts, comment trees and search results without an API key, a login or an OAuth token. Three modes on one input: a subreddit listing, a single post with its comments, or a search.

It works because it does not use the endpoint everything else used. Reddit closed the unauthenticated JSON API in late May 2026, and that is what broke most Reddit scrapers in circulation.

### What you get

- **Three modes from one actor**: subreddit listing, single post with its full comment tree, and search across Reddit or inside one subreddit
- **Score, comment count, author, subreddit and timestamp** on every post, read from Reddit's own data attributes rather than scraped out of rendered text
- **Comment depth**, so the reply tree is reconstructable rather than a flat list
- **`score_hidden` as its own field**, because Reddit deliberately hides comment scores for the first hour. A null score with `score_hidden: true` is a real state, not a parse failure
- **Post flags that matter for analysis**: NSFW, spoiler, original content, crosspost count, and whether a row is a promoted post rather than an organic one
- **Real pagination** that follows Reddit's own next cursor, so a 1.000-row run walks 40 pages correctly instead of re-fetching page one
- **All five sorts** (hot, new, top, rising, controversial) with the time window Reddit itself offers
- **No actor-start fee.** A run that returns nothing costs nothing

### Why this one still works

Before May 2026, appending `.json` to any Reddit URL returned clean JSON with no authentication. Nearly every open-source Reddit scraper was built on that, and nearly all of them now return 403. Adding an API key does not fix it either, because Reddit's bot detection blocks the request shape regardless of the token.

This actor does not use those endpoints. It reads a rendering surface Reddit still serves in full, re-measured across 27 request profiles and 7 surfaces on 2026-09-01, and it keeps a ranked ladder of fallbacks so a single surface change does not take the actor down. Requests go out through country-pinned residential exits, so results match what a reader in that country sees.

The fields come from structured attributes on each post rather than from rendered text, so score, comment count, author, subreddit, timestamp, NSFW and promoted flags stay correct across Reddit's redesigns instead of breaking on the next CSS change.

### Input

| Field | Type | Required | Default | What it does |
|---|---|---|---|---|
| `mode` | select | yes | `subreddit` | `subreddit`, `post` or `search` |
| `subreddit` | string | conditional | `webscraping` | Required in subreddit mode; optional in search mode to restrict the search |
| `post_url` | string | conditional | – | Required in post mode. Any Reddit post link, in any of its URL forms |
| `query` | string | conditional | – | Required in search mode |
| `sort` | select | no | `hot` | `hot`, `new`, `top`, `rising`, `controversial` |
| `time` | select | no | `all` | Window for the top and controversial sorts, and for search |
| `limit` | integer | no | `50` | Rows to return, 1 to 1000 |
| `proxy_country` | string | no | – | Two-letter country code for the exit |
| `retries` | integer | no | `4` | Retry attempts per page |

### Output

```json
{
  "position": 1,
  "type": "post",
  "id": "t3_1w39wno",
  "title": "Show HN: a small Rust crate for streaming JSON",
  "url": "https://www.reddit.com/r/webscraping/comments/1w39wno/...",
  "link_url": "https://www.reddit.com/r/webscraping/comments/1w39wno/...",
  "author": "alex_pushing40",
  "subreddit": "webscraping",
  "score": 35,
  "comments_count": 15,
  "created_at": "2026-08-27T02:38:44Z",
  "domain": "self.webscraping",
  "rank": 1,
  "is_nsfw": false,
  "is_promoted": false,
  "crossposts": 0,
  "selftext": "I built a fetcher that ...",
  "flair": null
}
```

Comment rows carry `type: "comment"`, plus `text`, `depth`, `post_id`, `score` and `score_hidden`.

### Use cases

**Monitoring what a community says about your product.** Search mode with your brand name, sorted by new, on a schedule. Because `created_at` and `score` come back as real values, you can separate a post that is quietly sitting at two upvotes from one that is climbing, which is the difference between noise and something you need to answer today.

**Building a dataset for a model.** Subreddit mode with a high limit gives you posts with their full self text; post mode gives you the whole discussion under any of them with the reply depth intact. `selftext` and `text` are plain text with the markup stripped, which is what an embedding pipeline wants.

**Tracking a subreddit's agenda over time.** Run `top` with `time: week` on a schedule and store the results. Which topics reach the top of a community, and at what score, is a trend signal that no analytics product sells you.

**Competitive and sentiment research.** Reddit is where people say what they actually think about tools they pay for. Search inside the subreddits where your category lives, keep the rows with `score` above a threshold, and you have a filtered feed of opinions that carried weight with other readers.

### How it compares

| | this actor | `trudax/reddit-scraper-lite` |
|---|---|---|
| Per 1.000 rows | **$2,50** | $4,00 |
| Actor-start fee | **none** | **$0,02 per GB on start** |
| 30-day run failure rate | 0% across validation runs | **11,8%** |
| Modes | **subreddit, post, search** | listing focused |
| Comment depth | **yes** | not stated |
| Distinguishes a hidden score from a missing one | **yes** | no |
| Promoted-post flag | **yes** | no |

Honest about the other side: `trudax/reddit-scraper-lite` has 7.070 monthly users and 38 reviews against our zero, and it has been running far longer. The reason to switch is that it fails roughly one run in eight and charges a start fee before any row arrives.

### Pricing

One event. `item` costs $0,0025 per post or comment returned, which is $2,50 per 1.000. All pricing is pay-per-event, so you only pay for rows you actually receive. No actor-start fee, no per-compute-unit charges, and a run that returns nothing costs nothing.

### Limits and gotchas

- **The `.json` endpoints are dead and no scraper can revive them.** Any tool still promising them is either using an authenticated token or is broken. This one reads HTML on purpose.
- **Comment scores are hidden for the first hour** by Reddit's own rule. Those rows come back with `score: null` and `score_hidden: true` rather than a fabricated zero.
- **Post mode returns the comments Reddit renders on the first page**, which is the top of the tree rather than every reply on a thousand-comment thread. Deep threads collapse behind "load more comments" links that are not followed.
- **Search results carry less detail than listings.** Reddit's search template omits the data attributes, so `id` and `created_at` can be empty there while title, author, score and subreddit are present.
- **Private, quarantined and banned subreddits return nothing**, which is correct rather than an error.
- **Requests are paced deliberately**, roughly one page per second with a jitter. A 1.000-row run takes about a minute, and pushing harder is what gets a scraper blocked.

### FAQ

**Can I scrape Reddit without an API key in 2026?**
Yes, but not the way most guides describe. The unauthenticated `.json` endpoints stopped working in late May 2026, which is why most open-source scrapers now return 403. This actor uses a different, still-served rendering surface with a ranked ladder of fallbacks, so it keeps returning full rows.

**Why do other Reddit scrapers return 403?**
Because they call `reddit.com/....json`, which now refuses unauthenticated requests regardless of IP, country or user-agent. It is not a proxy problem and a better proxy will not fix it.

**Can I get all the comments on a post?**
You get the comment tree Reddit renders on the post page, with depth, which is the top of the discussion. Replies hidden behind "load more comments" are not expanded.

**Does it work on private subreddits?**
No. Anything requiring a logged-in account is out of reach by design, since there is no credential in the input.

**Can I search inside one subreddit?**
Yes. Use search mode and set `subreddit` as well as `query`, and the search is restricted to that community.

### Related Actors

- [Google News Scraper](https://apify.com/s-r/google-news) — headlines and coverage for any topic
- [Google Search Results SERP](https://apify.com/s-r/free-google-search-results-serp---only-0-25-per-1-000-results) — organic rankings at $0,25 per 1.000
- [YouTube Comments Scraper](https://apify.com/s-r/youtube-comments) — comment threads from any video

# Actor input Schema

## `mode` (type: `string`):

Subreddit returns a listing of posts. Post returns one post plus its comment tree. Search returns results for a query, optionally inside one subreddit.

## `subreddit` (type: `string`):

Subreddit name without the r/ prefix. Required in subreddit mode. In search mode it is optional and restricts the search to that community instead of all of Reddit.

## `post_url` (type: `string`):

Full Reddit post URL. Required in post mode. Any of Reddit's URL forms works and every returned link is normalised to www.reddit.com.

## `query` (type: `string`):

What to search for. Required in search mode. Reddit's own search syntax works, including quoted phrases.

## `sort` (type: `string`):

How to order the results. Hot, new, top, rising and controversial apply to a subreddit listing. Search additionally accepts relevance and most-comments.

## `time` (type: `string`):

Only applies to the Top and Controversial sorts, and to search.

## `limit` (type: `integer`):

How many rows to return, 1 to 1000. A listing page carries 25 posts and the walk follows Reddit's own next cursor.

## `proxy_country` (type: `string`):

Two-letter country code for the exit, for example us or nl. Leave empty to let the proxy choose.

## `retries` (type: `integer`):

Retry attempts per page, each with a different crawler user-agent and TLS fingerprint.

## Actor input object example

```json
{
  "mode": "subreddit",
  "subreddit": "webscraping",
  "post_url": "https://www.reddit.com/r/n8n/comments/1rgczas/free_reddit_scraper_no_api_key_needed_free_n8n/",
  "query": "web scraping",
  "sort": "hot",
  "time": "all",
  "limit": 50,
  "proxy_country": "us",
  "retries": 4
}
```

# Actor output Schema

## `results` (type: `string`):

One row per post or comment.

## `summary` (type: `string`):

Mode, pages fetched and rows returned.

## `errors` (type: `string`):

Failures with a code and a redacted message.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "subreddit",
    "subreddit": "webscraping",
    "sort": "hot",
    "time": "all",
    "limit": 50,
    "retries": 4
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/reddit-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "subreddit",
    "subreddit": "webscraping",
    "sort": "hot",
    "time": "all",
    "limit": 50,
    "retries": 4,
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/reddit-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "subreddit",
  "subreddit": "webscraping",
  "sort": "hot",
  "time": "all",
  "limit": 50,
  "retries": 4
}' |
apify call s-r/reddit-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/reddit-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/rx8si9EwgPo8cr81T/builds/vkSkB8lhoiWusXfke/openapi.json
