# Reddit Subreddit Members Scraper With Source Posts (`scrapier/reddit-subreddit-members-scraper`) Actor

Scrape Reddit subreddit members and source posts to discover active users, usernames, post history, engagement, scores, and subreddit activity. Analyze communities, identify relevant audiences, research competitors, uncover leads, and build targeted datasets for marketing and market research.

- **URL**: https://apify.com/scrapier/reddit-subreddit-members-scraper.md
- **Developed by:** [Scrapier](https://apify.com/scrapier) (community)
- **Categories:** Automation, Lead generation, Social media
- **Stats:** 3 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Subreddit Scraper — Extract Participants and Source Posts

Reddit Subreddit Scraper reads a subreddit's post feed, comment firehose, keyword search, or a single redditor's overview, and returns every active public participant it finds — each one paired with the exact post or comment that surfaced them (title, permalink, score, real timestamp) plus a roll-up of everything else they did during the sweep. Every response is structured JSON, ready to pass directly to an LLM, index into a vector store, or feed into a monitoring pipeline. Point it at a community you track, and every run shows who is actually talking — not just how many people are subscribed.

***

### 🧭 What is Reddit Subreddit Scraper?

Reddit Subreddit Scraper queries one or more subreddits, redditors, or free-text search terms and returns the **active public participants** it finds in the feeds it reads, in typed JSON. It does not — and cannot — return a subreddit's subscriber list; Reddit has never published one. What makes this Actor's output different is that every participant row arrives with the exact post or comment that surfaced them still attached — `sourceTitle`, `sourcePermalink`, `sourceScore`, a real `sourceCreatedISO` timestamp — plus a roll-up of that person's contributions across the entire sweep. No Reddit account or login is required: the Actor reads `old.reddit.com` as a logged-out visitor.

Key capabilities:

- 📄 **Post feeds** — `new`, `hot`, `top` (with a time window), or `rising`
- 💬 **Comment firehose** — reads the subreddit's live comment stream, the surface that turns up the most participants no post feed shows
- 🔍 **Keyword search** — inside your listed subreddits or across all of Reddit
- 👤 **Direct redditor lookup** — pull one user's own post/comment overview
- 🧵 **Source evidence on every row** — the id, title, permalink, score and timestamp of the item that found them
- 📊 **Contribution roll-up** — how many times, in how many threads, and over what time span each participant showed up

***

### 🔍 What data can you get with Reddit Subreddit Scraper?

Every run can return five kinds of data: the participant summary, the source evidence attached to it, a per-participant contribution roll-up, an optional profile card, and — as two separate uncharged datasets — the raw contribution log and a run-accounting record.

| Result Type | Extracted Fields | Primary Use Case |
| --- | --- | --- |
| Participant summary | `username`, `userId`, `profileUrl`, `rowScope`, `postKarma`, `commentKarma`, `createdISO` | Who is active, and their account context |
| Source post/comment evidence | `sourceType`, `sourceId`, `sourceTitle`, `sourcePermalink`, `sourceScore`, `sourceCreatedISO`, `sourceSubreddit`, `sourceLinkFlair`, `sourceText`, `sourceTextSource`, `sourceUpvoteRatio`, `sourceAuthorFlair` | Auditing exactly what was said and where |
| Contribution roll-up | `contributionCount`, `postContributions`, `commentContributions`, `distinctThreadCount`, `discoverySurfaces`, `surfaceCount`, `activitySpanHours`, `topSourceScore`, `totalSourceScore` | Telling a regular apart from a one-off visitor |
| Full contribution log (uncharged) | `contributionType`, `contributionId`, `title`, `permalink`, `score`, `createdISO`, `subreddit`, `text`, `authorFlair` | Item-by-item audit of the roll-up above |
| Run diagnostics (uncharged) | `httpRequests`, `blockedResponses`, `realUserIdCoverage`, `sourceTextCoverage`, `surfaceFailures` | Confirming the run actually read content, not block pages |

#### 🧵 Source post evidence attached to every participant

This is the capability this Actor is built around: every participant row carries the exact post or comment that surfaced them, not just a username. That means `sourceTitle`, `sourcePermalink`, `sourceScore`, `sourceNumComments`, `sourceCreatedISO`, `sourceSubreddit`, `sourceLinkFlair`, and — when `enrichFromArchive` is on — `sourceText`, `sourceUpvoteRatio` and `sourceAuthorFlair` filled in from a third-party Reddit archive. You can click `sourcePermalink` and read the actual thread. A minimal example:

```json
{
  "username": "Ousret",
  "sourceType": "post",
  "sourceTitle": "Niquests 3.18 — 3 Years of Innovations in HTTP",
  "sourcePermalink": "https://www.reddit.com/r/Python/comments/1sackyi/niquests_318/",
  "sourceScore": 485,
  "sourceCreatedISO": "2026-04-02T09:27:46Z",
  "sourceText": "When I started working on Niquests, I dreamed about a no-compromise HTTP client…",
  "sourceTextSource": "arctic-shift"
}
```

#### 📊 Contribution roll-up across the sweep

Every participant is deduplicated once per run, and every post or comment of theirs that the sweep saw is rolled up onto that single row: `contributionCount`, the post/comment split, `distinctThreadCount`, which surfaces they were seen on, and `firstSeenISO` → `lastSeenISO` with the `activitySpanHours` between them. This is what turns a flat name list into a signal of who is a regular versus who showed up once.

***

### 🛠️ Why not build this yourself?

Reddit gives no stable, low-friction surface for this. Every `*.json` Reddit endpoint — `/new.json`, `/comments.json`, `/search.json`, `/user/<n>/about.json` — returns HTTP 403 to unauthenticated clients, so you're left parsing `old.reddit.com` HTML. Doing that reliably means fighting three separate problems at once: TLS fingerprinting (Chrome-family fingerprints are blocked; only Firefox/Safari fingerprints are served), HTTP 200 responses that carry no content (a "prove your humanity" interstitial returns 200, same as a real page), and proxy blocking (every Apify datacenter proxy group returns HTTP 403 on Reddit; only residential egress works). None of that is a one-time fix — fingerprint allow-lists and block pages both change without notice, so a hand-rolled scraper needs ongoing maintenance just to keep returning content instead of silently returning block pages that look like empty results.

⚠️ This Actor handles all three: it pins a Firefox/Safari TLS profile with a fallback list, gates every response on the presence of the expected content container rather than the HTTP status code, and pins the RESIDENTIAL Apify Proxy group regardless of what you select.

***

### 🧩 What's the difference between a subreddit's member list and an active-participant scrape?

A member list would be every account subscribed to a community — Reddit has never published that, full stop. The closest thing that ever existed was a subscriber *count* on `/r/<sub>/about.json`, and that endpoint now returns HTTP 403 to every unauthenticated client, so even the count is gone. An active-participant scrape is a different thing entirely: every account that authored a public post or comment in the feeds you point the Actor at.

The distinction matters because the two answer different questions. A subscriber count tells you how many people clicked "Join" at some point, most of whom never post — lurkers are the majority of any subreddit's subscriber count. An active-participant scrape tells you who is actually driving the conversation right now, with the receipt for each claim attached.

Reddit Subreddit Scraper only ever returns the second kind of data. Every row is explicit about it — `rowScope` states in plain language that the row is "an active public participant discovered from a post or comment (not a subscriber)" — and no subscriber count is ever emitted or estimated.

***

### 🚀 How to scrape Reddit with Reddit Subreddit Scraper?

1. Open the Actor on its Apify Store listing and click **Try for free** (or start it from the Apify Console if you already use it).
2. Add at least one subreddit, redditor or search term to `targets` — plain names, `r/<subreddit>`, `u/<username>`, or full URLs. No field is strictly required by the schema, but the run has nothing to sweep without at least one entry.
3. Set the real query controls: `sort_order` (`new` / `hot` / `top` / `rising`), `topTimeWindow` for `top` and searches, `maxPosts`, `maxComments`.
4. Start the run.
5. Download the results as JSON, CSV, Excel, XML or HTML from the Apify Console, or pull them with the Apify API / `apify-client`.

```json
{
  "targets": ["r/webscraping"],
  "sort_order": "top",
  "topTimeWindow": "month",
  "maxPosts": 50,
  "maxComments": 50
}
```

#### Running multiple subreddits, redditors or searches in one job

`targets` and `subreddits` are arrays — list as many subreddits, `u/` redditors and search keywords as you want, and they all run in the same job. Each is swept **sequentially, not in parallel**: the Actor reads one subreddit's feed and comment firehose to completion before moving to the next. `maxConcurrentUsers` only controls parallelism in the separate, optional profile-card step (`fetchDetails`), not the feed sweep itself — a long target list on a job with `fetchDetails` off will still take proportionally longer to sweep, not less.

***

### ⬇️ Input

Reddit Subreddit Scraper takes no required fields — you can start a run with defaults alone, though you'll get nothing back without at least one target. Every parameter below is optional.

| Parameter | Required | Type | Description | Example Value |
| --- | --- | --- | --- | --- |
| `targets` | No | Array of strings | Mixed entrypoints. Accepts full URLs, `r/<subreddit>`, `u/<username>`, or a plain keyword run as a Reddit search. Anything that isn't a subreddit or a redditor becomes a search term. | `["r/python", "webscraping", "u/spez"]` |
| `subreddits` | No | Array of strings | Plain subreddit names to sweep in addition to `targets`. | `["python"]` |
| `startUrls` | No | Array of strings | Alias of `targets`, used only when `targets` is empty. | `[]` |
| `sort_order` | No | String — enum `new`, `hot`, `top`, `rising` | Which subreddit feed to read. `new` = freshest, `hot` = front page, `top` = best of a window, `rising` = early movers. | `"new"` |
| `topTimeWindow` | No | String — enum `hour`, `day`, `week`, `month`, `year`, `all`; default `"week"` | Time window applied to the `top` feed and to keyword searches. | `"week"` |
| `maxPosts` | No | Integer, min `1`, max `1000`, default `10` | Posts to read per subreddit feed, per search, or per redditor overview. Reddit serves 100 per page; higher values paginate. | `50` |
| `maxComments` | No | Integer, min `0`, max `1000`, default `10` | Items to read from the subreddit's live comment firehose. `0` skips it. | `50` |
| `includeCommentFeed` | No | Boolean, default `true` | Read the comment firehose. | `true` |
| `searchWithinSubreddits` | No | Boolean, default `true` | On: search terms run with `restrict_sr` inside every listed subreddit. Off: searched across all of Reddit. | `true` |
| `enrichFromArchive` | No | Boolean, default `true` | Look up discovered ids on the Arctic Shift archive to add post body text, upvote ratio and author flair. | `true` |
| `emitContributionDataset` | No | Boolean, default `true` | Write one extra, uncharged row per post/comment to a `<runId>-contributions` dataset. | `true` |
| `minSourceScore` | No | Integer, min `0`, max `100000`, default `0` | Drop participants whose discovering items all scored below this. | `5` |
| `sourceTextKeywords` | No | Array of strings | Case-insensitive substring match over post title, body and flair. Matches echo back on `matchedKeywords`. | `["proxy", "captcha"]` |
| `keywordMatchAll` | No | Boolean, default `false` | Off: match any keyword. On: require all of them. | `false` |
| `minContributions` | No | Integer, min `1`, max `1000`, default `1` | Keep only participants seen this many times or more in this run. | `2` |
| `excludeAuthors` | No | Array of strings | Usernames to skip entirely, case-insensitive, `u/` optional. | `["AutoModerator"]` |
| `maxParticipants` | No | Integer, min `0`, max `100000`, default `0` | Hard ceiling on charged participant rows. `0` = no cap. Highest-scoring evidence kept first. | `500` |
| `fetchDetails` | No | Boolean, default `true` | Fetch karma and account-creation date from each participant's public profile page. | `true` |
| `maxConcurrentUsers` | No | Integer, min `1`, max `10`, default `3` | Parallel profile-card requests. | `3` |
| `requestDelay` | No | Integer, min `0`, max `10`, default `1` | Base pause in seconds before each request, plus jitter. | `1` |
| `proxyConfiguration` | No | Object (proxy editor), default `{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}` | Apify Proxy configuration. RESIDENTIAL is pinned regardless of what is selected — see the constraint below. | see below |

**Common pitfall:** typing a bare subreddit name like `python` into `targets` without an `r/` prefix routes it into a Reddit-wide **keyword search**, not the subreddit feed — only the dedicated `subreddits` field auto-classifies plain names as subreddits. Use `r/python` in `targets`, or put `python` in `subreddits`.

⚠️ **Proxy constraint:** residential egress is mandatory. Every Apify datacenter proxy group is hard-blocked by Reddit, so the Actor pins the `RESIDENTIAL` group regardless of what you configure here — only your chosen country or session is kept.

#### Example input

```json
{
  "targets": ["r/webscraping"],
  "subreddits": ["python"],
  "sort_order": "top",
  "topTimeWindow": "month",
  "maxPosts": 50,
  "maxComments": 50,
  "includeCommentFeed": true,
  "sourceTextKeywords": ["proxy", "captcha"],
  "minSourceScore": 5,
  "minContributions": 1,
  "excludeAuthors": ["AutoModerator"],
  "enrichFromArchive": true,
  "fetchDetails": true,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

***

### ⬆️ Output

Output is typed, normalized JSON with a consistent schema across runs, exportable from the Apify Console or API as JSON, CSV, Excel, XML or HTML. A run writes to up to three datasets: the default dataset (charged), and two optional, uncharged datasets — `<runId>-contributions` and `<runId>-diagnostics`.

#### Scraped results

Default dataset — one row per unique participant per run:

```json
[
  {
    "username": "Ousret",
    "userId": "t2_72iv8e3",
    "profileUrl": "https://reddit.com/user/Ousret",
    "totalKarma": null,
    "postKarma": 4312,
    "commentKarma": 1980,
    "createdUTC": 1553086000,
    "isGold": null,
    "iconImg": null,
    "rowScope": "active public participant discovered from a post or comment (not a subscriber)",
    "profileFetched": true,
    "profileFetchNote": null,
    "createdISO": "2019-03-20T12:46:40Z",
    "discoverySurface": "r/Python · top (t=week)",
    "sourceType": "post",
    "sourceId": "t3_1sackyi",
    "sourceTitle": "Niquests 3.18 — 3 Years of Innovations in HTTP",
    "sourcePermalink": "https://www.reddit.com/r/Python/comments/1sackyi/niquests_318_3_years_of_innovations_in_http/",
    "sourceScore": 485,
    "sourceNumComments": 87,
    "sourceCreatedUTC": 1775122066,
    "sourceCreatedISO": "2026-04-02T09:27:46Z",
    "sourceSubreddit": "Python",
    "sourceLinkFlair": "Showcase",
    "sourceRank": 3,
    "sourceIsNSFW": false,
    "sourceThreadId": "t3_1sackyi",
    "sourceParentPostAuthor": null,
    "sourceText": "When I started working on Niquests, I dreamed about a no-compromise HTTP client…",
    "sourceTextSource": "arctic-shift",
    "sourceUpvoteRatio": 0.97,
    "sourceAuthorFlair": null,
    "sourceIsSubmitter": null,
    "matchedKeywords": [],
    "contributionCount": 3,
    "postContributions": 1,
    "commentContributions": 2,
    "distinctThreadCount": 2,
    "contributionSubreddits": ["Python"],
    "discoverySurfaces": ["r/Python · top (t=week)", "r/Python · comments"],
    "surfaceCount": 2,
    "firstSeenUTC": 1775122066,
    "firstSeenISO": "2026-04-02T09:27:46Z",
    "lastSeenUTC": 1775225000,
    "lastSeenISO": "2026-04-03T14:02:11Z",
    "activitySpanHours": 28.57,
    "topSourceScore": 485,
    "totalSourceScore": 492,
    "contributionIds": ["t3_1sackyi", "t1_kzp9a1", "t1_kzp9b2"]
  },
  {
    "username": "corngoat",
    "userId": "t2_9fh2j",
    "profileUrl": "https://reddit.com/user/corngoat",
    "totalKarma": null,
    "postKarma": 812,
    "commentKarma": 5340,
    "createdUTC": 1421000000,
    "isGold": null,
    "iconImg": null,
    "rowScope": "active public participant discovered from a post or comment (not a subscriber)",
    "profileFetched": true,
    "profileFetchNote": null,
    "createdISO": "2015-01-11T18:13:20Z",
    "discoverySurface": "r/Python · comments",
    "sourceType": "comment",
    "sourceId": "t1_kzq3a0",
    "sourceTitle": "What's your favorite testing library in 2026?",
    "sourcePermalink": "https://www.reddit.com/r/Python/comments/1sadf2q/whats_your_favorite_testing_library/kzq3a0/",
    "sourceScore": 12,
    "sourceNumComments": null,
    "sourceCreatedUTC": 1775130000,
    "sourceCreatedISO": "2026-04-02T11:40:00Z",
    "sourceSubreddit": "Python",
    "sourceLinkFlair": null,
    "sourceRank": null,
    "sourceIsNSFW": null,
    "sourceThreadId": "t3_1sadf2q",
    "sourceParentPostAuthor": "seemsgud",
    "sourceText": "pytest, no contest — fixtures alone are worth the switch.",
    "sourceTextSource": "old.reddit",
    "sourceUpvoteRatio": null,
    "sourceAuthorFlair": null,
    "sourceIsSubmitter": null,
    "matchedKeywords": [],
    "contributionCount": 1,
    "postContributions": 0,
    "commentContributions": 1,
    "distinctThreadCount": 1,
    "contributionSubreddits": ["Python"],
    "discoverySurfaces": ["r/Python · comments"],
    "surfaceCount": 1,
    "firstSeenUTC": 1775130000,
    "firstSeenISO": "2026-04-02T11:40:00Z",
    "lastSeenUTC": 1775130000,
    "lastSeenISO": "2026-04-02T11:40:00Z",
    "activitySpanHours": null,
    "topSourceScore": 12,
    "totalSourceScore": 12,
    "contributionIds": ["t1_kzq3a0"]
  },
  {
    "username": "webscrape_dev",
    "userId": "t2_31kx0",
    "profileUrl": "https://reddit.com/user/webscrape_dev",
    "totalKarma": null,
    "postKarma": 210,
    "commentKarma": 990,
    "createdUTC": 1601400000,
    "isGold": null,
    "iconImg": null,
    "rowScope": "active public participant discovered from a post or comment (not a subscriber)",
    "profileFetched": false,
    "profileFetchNote": "profile page blocked",
    "createdISO": null,
    "discoverySurface": "r/webscraping · search 'proxy'",
    "sourceType": "post",
    "sourceId": "t3_1sbcd3",
    "sourceTitle": "Residential vs datacenter proxies for anti-bot heavy sites",
    "sourcePermalink": "https://www.reddit.com/r/webscraping/comments/1sbcd3/residential_vs_datacenter_proxies/",
    "sourceScore": 64,
    "sourceNumComments": 21,
    "sourceCreatedUTC": 1775050000,
    "sourceCreatedISO": "2026-04-01T14:26:40Z",
    "sourceSubreddit": "webscraping",
    "sourceLinkFlair": "Discussion",
    "sourceRank": 7,
    "sourceIsNSFW": false,
    "sourceThreadId": "t3_1sbcd3",
    "sourceParentPostAuthor": null,
    "sourceText": null,
    "sourceTextSource": null,
    "sourceUpvoteRatio": null,
    "sourceAuthorFlair": null,
    "sourceIsSubmitter": null,
    "matchedKeywords": ["proxy"],
    "contributionCount": 1,
    "postContributions": 1,
    "commentContributions": 0,
    "distinctThreadCount": 1,
    "contributionSubreddits": ["webscraping"],
    "discoverySurfaces": ["r/webscraping · search 'proxy'"],
    "surfaceCount": 1,
    "firstSeenUTC": 1775050000,
    "firstSeenISO": "2026-04-01T14:26:40Z",
    "lastSeenUTC": 1775050000,
    "lastSeenISO": "2026-04-01T14:26:40Z",
    "activitySpanHours": null,
    "topSourceScore": 64,
    "totalSourceScore": 64,
    "contributionIds": ["t3_1sbcd3"]
  }
]
```

`sourceText` is `null` on the third row because `enrichFromArchive` had no matching record for that post at the time it ran — post bodies are not present in Reddit's listing HTML, so without an archive match the field stays honestly empty rather than being filled with a guess.

#### Secondary dataset — `<runId>-contributions` (uncharged, when `emitContributionDataset` is on)

One row per individual post/comment behind each participant: `username`, `userId`, `contributionType`, `contributionId`, `title`, `permalink`, `score`, `numComments`, `createdUTC`, `createdISO`, `subreddit`, `linkFlair`, `rank`, `threadId`, `parentPostAuthor`, `text`, `textSource`, `upvoteRatio`, `authorFlair`, `discoverySurface`, `matchedKeywords`.

#### Third dataset — `<runId>-diagnostics` (uncharged, always written)

One run-accounting record: `recordType`, `runId`, `elapsedSeconds`, `httpRequests`, `blockedResponses`, `transportErrors`, `tlsProfileUsed`, `rawItems`, `itemsAfterFilters`, `uniqueParticipantsFound`, `participantsPushedAndCharged`, `contributionRowsUncharged`, `droppedByMinSourceScore`, `droppedByKeywords`, `droppedByExcludeAuthors`, `droppedByMinContributions`, `realUserIdCoverage`, `sourceTextCoverage`, `archivePostsMatched`, `archiveCommentsMatched`, `chargeLimitReached`, `surfaceFailures`, `scopeNote`.

**Preserved-but-uncollectable columns:** `totalKarma`, `isGold` and `iconImg` are kept on every default-dataset row for backwards compatibility but are always `null`. They only ever existed on `/user/<name>/about.json`, which now returns HTTP 403 to every unauthenticated client, so no live surface carries them — the Actor emits an honest `null` rather than a fabricated `0`.

***

### 📈 How can I use the data extracted with Reddit Subreddit Scraper?

- **🔬 Community researchers:** measure who actually drives a subreddit's conversation and on which threads, using `contributionCount`, `distinctThreadCount` and `sourceText` together instead of raw post counts alone.
- **🛠️ Community managers and moderators:** separate regulars from drive-by accounts with `minContributions`, and read what each person actually said via `sourceText` before deciding how to respond.
- **🤖 AI engineers and LLM developers:** feed a query, receive structured participant + source-evidence JSON, and pass it to a model as grounded context for a monitoring or research agent — no separate scraping step in the agent's own code.
- **📊 Market and brand researchers:** pull the people discussing a product category with the exact sentence they wrote next to their name via `sourceTextKeywords`, rather than working from anonymized aggregate counts.

***

### 🔄 How do you monitor participant activity over time?

Monitoring here means running the same target list on a schedule and diffing the participant set between runs, rather than treating a single sweep as a one-time snapshot. Because every row carries `firstSeenISO`, `lastSeenISO`, `contributionCount`, `surfaceCount` and `topSourceScore`, a second run against the same subreddits tells you who is new, who dropped off, and whose activity intensified — without re-reading the whole history each time.

The fields worth diffing between runs: compare `username` sets to find new versus returning participants; compare `contributionCount` and `totalSourceScore` per returning username to see whose activity grew or shrank; compare `topSourceScore` to catch someone whose post or comment suddenly took off. A `discoverySurfaces` change (a participant who only showed up in comments last time now also appearing in `top`) is often the earliest signal that something is gaining traction.

A practical loop: schedule a run across your target subreddits daily or weekly, keep the previous run's dataset export, join on `username`, and alert on whichever delta matters to you — a new participant with a high `sourceScore`, or a regular whose `totalSourceScore` jumped. Reddit Subreddit Scraper has no built-in scheduler of its own; set this up with Apify's **Schedules** feature in the Console (or the Apify API), which starts the Actor with the same input on a cron interval.

***

### 🔗 Integrate Reddit Subreddit Scraper and automate your workflow

Reddit Subreddit Scraper works with any language or tool that can send an HTTP request, through the standard Apify API.

#### REST API with Python

```python
import requests

ACTOR_ID = "your-username~reddit-subreddit-members-scraper-with-source-posts"
TOKEN = "apify_api_your_token"

run = requests.post(
    f"https://api.apify.com/v2/acts/%7BACTOR_ID%7D/run-sync-get-dataset-items",
    headers={"Authorization": f"Bearer {TOKEN}"},
    json={"targets": ["r/webscraping"], "maxPosts": 50, "maxComments": 50},
    timeout=300,
)
participants = run.json()
for p in participants[:3]:
    print(p["username"], "->", p["sourceTitle"])
```

Find the exact Actor ID and a ready-made call on the Actor's **API** tab in the Apify Console.

#### Scheduled monitoring and delivery

Use the Apify Console's **Schedules** tab to re-run the same input on a cron interval, and the **Integrations** tab to trigger a webhook on run success or failure. There is no push-delivery feature beyond that — pull results after each scheduled run via the API or a webhook-triggered fetch of the dataset.

***

### ⚖️ Is it legal to scrape Reddit participant data?

Reddit Subreddit Scraper reads only what `old.reddit.com` serves a logged-out visitor — the same posts, comments and usernames anyone can see without an account. It does not log in, does not bypass any authentication wall, and collects no private messages, emails or account-recovery details.

Every row does name an identifiable person, though: a Reddit username tied to real posts, karma and an account-creation date. Public posting is not consent to be contacted, profiled, or added to a marketing list, and compiling this kind of personal data falls under GDPR, CCPA and equivalent data-protection regimes wherever your organization or your data subjects are covered — separately from whatever Reddit's own terms of service say about automated access. Scraping for one-off research carries a different risk profile than scraping to build a permanent, resold dataset, or to train a model on identifiable people.

Consult your legal team for commercial use cases involving bulk storage of personal data.

***

### ❓ Frequently asked questions

#### Does Reddit Subreddit Scraper return a subreddit's member or subscriber list?

No, and nothing can. Reddit has never published subreddit membership, and the one proxy for it — a subscriber count on `/r/<sub>/about.json` — now returns HTTP 403 to every unauthenticated client. Every row is an active participant discovered from a public post or comment, not a subscriber; `rowScope` states this in plain language on every row.

#### Can I restrict a keyword search to only the subreddits I listed?

Yes. `searchWithinSubreddits` (default `true`) runs your search terms with Reddit's `restrict_sr` inside every subreddit in `targets`/`subreddits`, and each row records which one it came from. Turn it off to search across all of Reddit instead.

#### Which feed should I read — new, hot, top or rising?

They're not redundant, but two of them are close: the Actor's own input schema documents that `new` and `hot` shared 98.6% of their authors on a measured r/python run, so `hot` rarely adds new people beyond `new`. `top` (with `topTimeWindow`) and the comment firehose (`includeCommentFeed`) are the surfaces that add the most distinct participants.

#### How does Reddit Subreddit Scraper handle Reddit's anti-bot measures?

It pins a Firefox/Safari TLS impersonation profile (Chrome-family fingerprints are blocked on Reddit) with a fallback list if a profile stops working, routes every request through Apify's RESIDENTIAL proxy group (every datacenter group is blocked), and gates each response on the presence of the expected content container rather than trusting the HTTP status code — since Reddit serves block and interstitial pages as HTTP 200.

#### Does Reddit Subreddit Scraper extract the source post or comment for every participant?

Yes — under `sourceType`, `sourceId`, `sourceTitle`, `sourcePermalink`, `sourceScore`, `sourceCreatedISO`, `sourceSubreddit` and related fields. `sourceText` is `null` when `enrichFromArchive` is off or the third-party archive has no matching record yet (post bodies are not present in Reddit's own listing HTML). `sourceScore` is `null` when Reddit itself hides the score, which it does on very new comments.

#### How many participants does Reddit Subreddit Scraper return per run?

That depends entirely on your inputs, not a platform-wide cap: `maxPosts` (1–1000, default 10) and `maxComments` (0–1000, default 10) bound how many items are read per feed, `minContributions` (default 1) and `maxParticipants` (0–100000, default 0 = no cap) bound how many deduplicated participants are kept and charged. Reddit itself serves at most 100 items per page, so higher `maxPosts`/`maxComments` values page through more requests.

#### How do I monitor a subreddit's active participants over time?

Schedule the same input to run repeatedly with Apify's Schedules feature, keep each run's dataset export, and join on `username` across runs. Compare `contributionCount`, `totalSourceScore` and `discoverySurfaces` to see who is new, who returned, and whose activity or score grew.

#### Does Reddit Subreddit Scraper work with Claude, ChatGPT and AI agent frameworks?

It's callable as a plain HTTP endpoint through the Apify API, which any agent framework can call — an agent issues a query, receives structured participant and source-evidence JSON back, and uses it as grounded context before answering.

#### How does Reddit Subreddit Scraper compare to other Reddit scrapers?

Evaluate any Reddit scraper on the same axes: does each participant row carry the exact post or comment that surfaced them, or just a username; does it roll up a person's contributions across the whole sweep or count each item separately; and does it emit an honest `null` for fields Reddit no longer exposes (like total karma) rather than a fabricated value. This Actor's default dataset is built around answering yes to all three.

#### Can I use Reddit Subreddit Scraper without managing proxies or a Reddit account?

Yes. The Actor forces Apify's RESIDENTIAL proxy group internally regardless of your proxy settings, since Reddit blocks every Apify datacenter IP, and it reads Reddit as a logged-out visitor — no Reddit login or API credentials are needed. You only need an Apify account to run it.

***

### 💬 Your feedback

Found a bug, a field that no longer matches Reddit's markup, or a use case this Actor doesn't cover yet? Let us know through the Actor's page on the Apify Store — open an issue from the **Issues** tab or contact Scrapier support directly. Reports on real breakages get fixed fastest.

# Actor input Schema

## `targets` (type: `array`):

Mixed entrypoints. Accepts full URLs (https://www.reddit.com/r/python), r/<subreddit>, u/<username>, or a plain keyword that is run as a Reddit search. Anything that is not a subreddit or a redditor becomes a search term.

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

Plain subreddit names to sweep in addition to the list above, e.g. python, webscraping, learnprogramming.

## `startUrls` (type: `array`):

Alias kept for backwards compatibility with older run configurations. Used only when the first list is empty.

## `sort_order` (type: `string`):

new = freshest participants · hot = current front page (measured 98.6% overlap with new on r/python, so it rarely adds people) · top = highest-scoring in the chosen window · rising = early movers (small feed).

## `topTimeWindow` (type: `string`):

Applied to the 'top' feed and to keyword searches. Reddit silently treats a missing window as 'day', so this is always sent explicitly.

## `maxPosts` (type: `integer`):

How many posts to read per subreddit feed, per search, or per redditor overview. Reddit serves 100 per page; higher values paginate.

## `maxComments` (type: `integer`):

How many items to read from the subreddit's live comment firehose. Set 0 to skip it. The comment feed is the surface that adds the most people the post feeds never show.

## `includeCommentFeed` (type: `boolean`):

Turn off to collect participants from post feeds only. Measured on r/python: only 2.1% of comment-feed authors also appear in the 'new' post feed.

## `searchWithinSubreddits` (type: `boolean`):

On: a search term is run with restrict\_sr inside every subreddit you listed, and every row says which one it came from. Off: the term is searched across all of Reddit.

## `enrichFromArchive` (type: `boolean`):

Looks up the exact post and comment ids already discovered on arctic-shift.photon-reddit.com to add post body text, upvote ratio and author flair. Third-party archive, no SLA, roughly one hour behind live. When it is unavailable those fields stay null and sourceTextSource records which surface supplied the text.

## `emitContributionDataset` (type: `boolean`):

Writes one extra, uncharged row per post/comment into a separate '<runId>-contributions' dataset, so the summary on each participant row can be audited item by item.

## `minSourceScore` (type: `integer`):

Drop participants whose posts/comments all scored below this. Items whose score Reddit hides are treated as not meeting the floor. Leave at 0 to keep everything.

## `sourceTextKeywords` (type: `array`):

Case-insensitive substring match over the post title, the post/comment body and the link flair. Matches are listed back on each row in matchedKeywords, so the filter is auditable.

## `keywordMatchAll` (type: `boolean`):

Off: keep an item that matches any keyword. On: keep only items that match all of them.

## `minContributions` (type: `integer`):

Keep only participants seen this many times or more across everything that was swept. 1 keeps everyone; 2+ isolates regulars from one-off visitors.

## `excludeAuthors` (type: `array`):

Skip these accounts entirely - moderators, AutoModerator, known bots. Case-insensitive, with or without the u/ prefix.

## `maxParticipants` (type: `integer`):

Hard ceiling on how many participants are pushed and charged. 0 means no cap. Highest-scoring evidence is kept first.

## `fetchDetails` (type: `boolean`):

Fetches old.reddit.com/user/<name>/ once per participant. Total karma, Reddit Gold and avatar are NOT collectable any more (they only ever existed on about.json, which now returns 403) - those columns stay null and profileFetched tells you whether the page was actually read.

## `maxConcurrentUsers` (type: `integer`):

How many profile-card requests run at once. Lower it if profile pages start coming back blocked.

## `requestDelay` (type: `integer`):

Base pause added before each request, with a small random jitter on top.

## `proxyConfiguration` (type: `object`):

Residential egress is mandatory for Reddit: every Apify datacenter group returned HTTP 403 on 100% of requests when measured. The actor pins the RESIDENTIAL group and keeps any country you choose.

## Actor input object example

```json
{
  "targets": [
    "r/python",
    "webscraping",
    "u/spez"
  ],
  "subreddits": [
    "python"
  ],
  "topTimeWindow": "week",
  "maxPosts": 10,
  "maxComments": 10,
  "includeCommentFeed": true,
  "searchWithinSubreddits": true,
  "enrichFromArchive": true,
  "emitContributionDataset": true,
  "minSourceScore": 0,
  "keywordMatchAll": false,
  "minContributions": 1,
  "excludeAuthors": [
    "AutoModerator"
  ],
  "maxParticipants": 0,
  "fetchDetails": true,
  "maxConcurrentUsers": 3,
  "requestDelay": 1,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

All scraped items in the Actor's default dataset.

# 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 = {
    "targets": [
        "r/python",
        "webscraping",
        "u/spez"
    ],
    "subreddits": [
        "python"
    ],
    "excludeAuthors": [
        "AutoModerator"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapier/reddit-subreddit-members-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 = {
    "targets": [
        "r/python",
        "webscraping",
        "u/spez",
    ],
    "subreddits": ["python"],
    "excludeAuthors": ["AutoModerator"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapier/reddit-subreddit-members-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 '{
  "targets": [
    "r/python",
    "webscraping",
    "u/spez"
  ],
  "subreddits": [
    "python"
  ],
  "excludeAuthors": [
    "AutoModerator"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call scrapier/reddit-subreddit-members-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapier/reddit-subreddit-members-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/LgaRZzaCBsD5LKeo3/builds/jfaRoJUrK0cuFI6BA/openapi.json
