# Reddit Scraper (subreddit posts, search, comments, no login) (`datahamster/reddit-posts`) Actor

Scrape Reddit subreddit listings (new, hot, top, rising) and search results: one row per post with title, text, score, comments, flair and domain. Optional comment rows per post. No login, no author names or handles collected. Monitor mode alerts only on new posts, never on score churn.

- **URL**: https://apify.com/datahamster/reddit-posts.md
- **Developed by:** [Viktor Dubnytskiy](https://apify.com/datahamster) (community)
- **Categories:** Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 result items

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Reddit Scraper (subreddit posts, search, comments, no login)

Get subreddit listings (new, hot, top, rising) and site-wide search results from Reddit's own public `.json` API — one row per post, with an optional row per comment. No Reddit account, no login, no cookies.

### What you get

Real rows from the example dataset (subreddit `webscraping`, sort `new`):

| title | score | commentCount | domain | source |
|---|---|---|---|---|
| "What browsers should be paired with cdp's like patchright or pydoll?" | `2` | `4` | `self.webscraping` | `r/webscraping/new` |
| "Low-latency scraping to semi-automated checkout flow" | `5` | `4` | `self.webscraping` | `r/webscraping/new` |
| "Computer Vision + mouse and keyboard scraper?" | `6` | `13` | `self.webscraping` | `r/webscraping/new` |

Full row (post): `id`, `url`, `type`, `subreddit`, `title`, `text`, `linkUrl`, `domain`, `score`, `upvoteRatio`, `commentCount`, `flair`, `isNsfw`, `isVideo`, `thumbnailUrl`, `createdAt`, `source`, `query`, `scrapedAt`. Comment rows (`type: comment`) swap the post-only fields for `postId`, `postUrl`, `depth`, `parentId`.

No usernames, no author flair, no avatars — post and comment authors are dropped entirely. Only public post/comment text and counters are collected; the subreddit itself is the entity, not the people posting in it.

### Use cases

- Track a subreddit for new posts (monitor mode) without polling Reddit yourself or maintaining OAuth credentials.
- Pull recent discussion and comment threads for a topic across all of Reddit via search.
- Build a dataset of post titles, scores and flair for a set of subreddits to analyse trends over time.

### Try it in 10 seconds

Hit **Start**/**Try it** — the input already works: `subreddits: ["webscraping"]`, `sort: "new"`, `maxPostsPerSource: 100`, `maxItems: 200`, nothing required.

To watch a subreddit for new posts only: save the task, set **Mode** to `monitor`, and put it on a schedule (Apify → Schedules → cron `0 8 * * 1` for weekly). Each run then returns only posts that are new since last time — a score or comment-count change overnight never triggers a false "change" event.

### How it works

Each subreddit and search query is read through Reddit's own `<subreddit>/<sort>.json` and `search.json` endpoints — the same JSON the Reddit web app itself uses, paginated with the `after` cursor. Comments (optional) come from the post's own `comments/<id>.json` endpoint, flattened up to two reply levels. A short page or a page whose posts have all been seen already ends pagination for that source.

**Proxy**: Reddit answers `.json` requests from a plain or residential exit with a 403 verification page; this actor always reads through Apify's Web Unblocker, billed per request on top of the flat result price below.

### Input

| Field | Meaning | Default |
|---|---|---|
| `subreddits` | Subreddit names or URLs to list, e.g. `webscraping` | `["webscraping"]` |
| `sort` | `new`, `hot`, `top` or `rising` | `new` |
| `timeRange` | Time window for `sort=top` | `week` |
| `searches` | Site-wide search queries | empty |
| `searchSort` | `relevance`, `new` or `top` | `relevance` |
| `maxPostsPerSource` | Posts fetched per subreddit/query | `100` |
| `includeComments` | Also fetch comment rows per post | `false` |
| `maxCommentsPerPost` | Comment rows kept per post | `50` |
| `maxItems` | Stop after this many rows total | `200` |
| `mode` | `scrape` or `monitor` (only new posts since last run) | `scrape` |
| `monitorStateId`, `webhookUrl`, `telegramBotToken`, `telegramChatId` | Monitor-mode state key and alert targets | empty |

### Pricing

| Event | Price |
|---|---|
| result | $0.002 per row ($2 per 1,000) |
| monitor-check | $0.006 per monitor run |
| change | $0.002 per new post |

Charged only for rows actually pushed. Web Unblocker proxy traffic is billed by Apify on top of the result price.

### Why this actor

- No Reddit account, no OAuth app registration, no rate-limit management on your side.
- Comment threads in the same run as the posts that started them, with `maxCommentsPerPost` keeping the bill predictable.
- Monitor mode keys strictly on the post id, so it alerts you when a genuinely new post appears — a post's score or comment count changing overnight never triggers a false "change" event.
- A run that finds nothing pushes nothing and charges no result events; the run summary explains why (banned/private/nonexistent subreddit vs. an actual wall) instead of leaving you guessing.

### Limits

- A private, banned or quarantined subreddit, or a subreddit that does not exist, is skipped (Reddit answers all three with the same HTTP 404) — it is not treated as a block.
- `text` and comment `text` are truncated at 5,000 characters.
- No vote data beyond the public score and upvote ratio Reddit itself publishes; no per-user voting history.

### FAQ

**Does it need a Reddit account or API key?** No. Every request goes through the same public `.json` endpoints a logged-out browser can read.

**Are usernames included?** No. Author names, flair and avatars are dropped from both post and comment rows; only the subreddit (a community, not a person) and the post/comment content are kept.

**What happens when a subreddit is empty or doesn't exist?** No rows are pushed for it and no result events are charged for it. The `RUN_SUMMARY` record in the run's key-value store separates a genuinely missing/banned/private subreddit from an actual verification wall.

### Changelog

- 0.1: initial release — subreddit listings, site search, optional comment rows, monitor mode keyed on post id.

***

If this actor saved you time, a short review on its Store page genuinely helps other people find it. Found a bug or need a field that is missing? Open a ticket on the **Issues** tab.

# Actor input Schema

## `maxItems` (type: `integer`):

Stop after this many results (you are charged only for pushed items)

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

scrape = full results; monitor = only new/changed items since the previous run of this task

## `monitorStateId` (type: `string`):

Optional state id when not running as a saved task (monitor mode)

## `webhookUrl` (type: `string`):

POST a change summary here in monitor mode

## `telegramBotToken` (type: `string`):

Optional: bot token for monitor-mode change summaries

## `telegramChatId` (type: `string`):

Optional: chat id that receives monitor-mode summaries

## `subreddits` (type: `array`):

Subreddit names or URLs to list posts from, one per line, e.g. "webscraping", "r/dataengineering", "https://www.reddit.com/r/SaaS/".

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

How each subreddit listing is sorted, e.g. "new".

## `timeRange` (type: `string`):

Time window for Sort = Top (and for Search sort = Top), e.g. "week".

## `searches` (type: `array`):

Site-wide Reddit search queries, one per line, e.g. "apify", "web scraping api". Combine with or use instead of Subreddits.

## `searchSort` (type: `string`):

How Search queries results are sorted, e.g. "relevance".

## `maxPostsPerSource` (type: `integer`):

How many posts to fetch per subreddit and per search query before moving to the next one, e.g. 100.

## `includeComments` (type: `boolean`):

true = also fetch up to "Max comments per post" comment rows for every post found (one extra request per post). false = post rows only. Example: false.

## `maxCommentsPerPost` (type: `integer`):

How many comment rows to keep per post when Include comments is on, e.g. 50.

## Actor input object example

```json
{
  "maxItems": 200,
  "mode": "scrape",
  "subreddits": [
    "webscraping"
  ],
  "sort": "new",
  "timeRange": "week",
  "searchSort": "relevance",
  "maxPostsPerSource": 100,
  "includeComments": false,
  "maxCommentsPerPost": 50
}
```

# Actor output Schema

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

All pushed rows (dataset, JSON)

## `resultsTable` (type: `string`):

Dataset in the Console viewer

## `runSummary` (type: `string`):

RUN\_SUMMARY record

# 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 = {
    "subreddits": [
        "webscraping"
    ],
    "maxPostsPerSource": 100,
    "maxCommentsPerPost": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("datahamster/reddit-posts").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 = {
    "subreddits": ["webscraping"],
    "maxPostsPerSource": 100,
    "maxCommentsPerPost": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("datahamster/reddit-posts").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 '{
  "subreddits": [
    "webscraping"
  ],
  "maxPostsPerSource": 100,
  "maxCommentsPerPost": 50
}' |
apify call datahamster/reddit-posts --silent --output-dataset

```

## MCP server setup

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

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/pkApvIKcitOi7Dq1W/builds/fOlrEOTXiMT09SZcd/openapi.json
