# Reddit Scraper API - Posts, Comments & Monitoring (`thirdwatch/reddit-scraper`) Actor

Scrape public Reddit posts, search, subreddits, media, and nested comments or monitor only newly observed posts. Anonymous read-only OAuth; no browser, proxy, login, cookies, or API key.

- **URL**: https://apify.com/thirdwatch/reddit-scraper.md
- **Developed by:** [Thirdwatch](https://apify.com/thirdwatch) (community)
- **Categories:** Social media, Lead generation
- **Features:** Limited permissions
- **Stats:** 391 total users, 55 monthly users, 81.7% runs succeeded, 5 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
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 API - Posts, Comments, Search & Monitoring

> **Thirdwatch portfolio:** 8,800+ users across 140+ public Actors, 2M+ records delivered, >95% run success. [Explore all Thirdwatch Actors](https://apify.com/thirdwatch).

### What you get

Extract public Reddit posts, subreddit listings, global search results, self-post text, engagement, media, and comments through anonymous read-only access. No Reddit login or user-supplied API key is required.

### Why this Actor

- **Anonymous access** — structured JSON results without a Reddit login or user-supplied API key.
- **100 posts per page** — paginate automatically to 1,000 posts per query.
- **Three query modes in one field** — global search, subreddit listings, and search within a subreddit.
- **Full public post bodies** — self-post text, media, flair, awards, crossposts, and moderation flags arrive in the structured response.
- **Comments included in the post price** — embed up to 100 public comments without paying per comment row. Available detail depends on the source, as described below.
- **Persistent new-post monitoring** — the first run creates a baseline; later complete runs return only unseen post IDs.
- **Zero unchanged result charges** — a scheduled monitor with no new posts writes no dataset rows.
- **No duplicate billing** — overlapping queries, URLs, and subreddit pages are deduplicated by Reddit post ID across the run.

### Query patterns

| Input | Behavior |
| --- | --- |
| `AI agents` | Search all public Reddit posts |
| `r/programming` | Browse a public subreddit using the selected sort |
| `r/programming: Python 3.14` | Search within one subreddit |
| `startUrls` | Paginate an existing Reddit listing/search page or fetch a post URL |
| `postUrls` | Fetch exact public posts and optionally their comments |

For a `startUrl` with an `after` or `before` cursor, pagination starts at that cursor. If the requested listing is unavailable, the Actor does not substitute a different listing whose cursor may mean something else.

URLs must point to supported Reddit pages; `postUrls` must point to individual Reddit posts. If a supplied URL is invalid, the run stops so it does not return results for an unintended target.

`minScore`, `skipPinnedPosts`, and `newerThan` apply to both listings and exact post URLs. The default minimum score is 0, so set a negative `minScore` if you also want negative-scoring posts. Invalid `newerThan` values stop the run. If a post's creation time cannot be verified while this date filter is active, the Actor omits that post and reports an incomplete target rather than guessing.

#### Basic subreddit run

```json
{
  "queries": ["r/programming", "r/python"],
  "sort": "new",
  "maxResults": 100
}
```

#### Global and subreddit-specific research

```json
{
  "queries": [
    "AI coding agents",
    "r/SaaS: customer support automation"
  ],
  "sort": "relevance",
  "timeFilter": "month",
  "maxResults": 250,
  "minScore": 5
}
```

#### Scheduled new-post monitoring

```json
{
  "queries": ["r/devops: alternative to", "r/sysadmin: recommend"],
  "sort": "new",
  "skipPinnedPosts": true,
  "maxResults": 50,
  "includeComments": true,
  "maxCommentsPerPost": 20,
  "monitorMode": "new-posts",
  "monitorStoreName": "infrastructure-buyer-signals"
}
```

Save that input as an Apify Task and attach a Schedule. The first successful run emits the current baseline with `changeType: "baseline"`. Later runs using the same monitor name emit posts this watch has not seen, with `changeType: "new_post"`. The Actor commits state after publishing rows, providing at-least-once delivery. A target that cannot be read keeps its last checkpoint and is tried again on the next run.

When queries overlap, the Actor emits each post once while retaining a separate recent window for each query's continuity check.

Use one `monitorStoreName` per independent watch. Cloud runs use a lock to prevent overlapping runs of the same monitor; a run waits up to 30 seconds for it, then stops and can be retried. After an interrupted run, a retry may need to wait for the lock to expire. Local runs do not have this protection. Changing a query, sort, or filter changes the cohort; use a new monitor name. `newerThan` remains available for one-off timestamp-filtered exports but is not needed for persistent monitoring.

If a run writes an alert but stops before saving its state, a retry can return that post again. Deduplicate downstream by monitor name and post `id` when repeats matter.

If the run's spending limit prevents some alerts from being saved, the monitor leaves its state unchanged. Increase the limit before retrying; alerts already written in the interrupted batch may be repeated.

For newest-first watches, a full result window with no previously seen posts can indicate missed posts. The Actor checks just beyond the window for a known post. If it cannot confirm continuity, the alerts are still delivered, the target is listed as incomplete with the reason `window_gap`, and its last complete checkpoint is kept. Increase `maxResults` or schedule runs more often. With `allowIncompleteMonitorFallback: false`, the run instead stops without writing alerts or changing the baseline. This check can report a gap even when no posts were missed, and it cannot detect every possible gap.

`allowIncompleteMonitorFallback` is on by default, so a watch keeps running when keyword search or a New, Rising, or Hot subreddit listing is unavailable. Hot recovery is limited to named subreddits. Keyword searches use Reddit's app search when the regular search is unavailable, and newest-first subreddit watches keep their complete feed while it answers. The alternative can miss posts or use a different order, so every alert from an affected run has `monitoringComplete: false`. Check the run's `OUTPUT` key-value record: `monitoringSourceStatus: "partial"` lists the affected `incompleteTargets`, including when no alerts are returned, with reasons under `incompleteReasons` such as `rate_limited`, `deadline`, `page_limit`, or `window_gap`.

On these sources, a post raises a `new_post` alert only when it was created after the watch's last check, less a six-hour allowance for slow search indexing, and is not older than that target's baseline. Older posts the watch never saw are remembered without an alert or a result charge, and `olderPostsNotAlerted` in `OUTPUT` shows how many. A post that Reddit indexes later than the allowance can be missed. A target that fails keeps its checkpoint while other targets still deliver, and the run fails only when no target returns data. A first run using the fallback is an incomplete baseline.

Set `allowIncompleteMonitorFallback: false` to require complete data. Such a watch stops without writing alerts or state whenever a target is incomplete, which can include most keyword searches while Reddit limits its regular search. This option does not make monitoring complete.

To use the incomplete alternative directly for keyword searches, set `preferIncompleteSearch: true`. It can miss posts or return a different order, and all affected rows have `discoveryComplete: false`. The incomplete-monitor behavior above applies to monitors, and this option cannot be combined with `allowIncompleteMonitorFallback: false`. This option is off by default and does not change subreddit listings. It does not retry another source after a rate limit. Explicit search-page cursors from a different source cannot be used with this option.

For a single-word search inside a named subreddit, set `includeAdultSearchSupplement: true`, `sort: "new"`, and `timeFilter: "all"` to also check up to 25 recent subreddit posts for adult-marked literal title or body matches. This selects incomplete app search directly and adds requests and latency; the extra requests can be rate-limited. Matching supplement rows have `discoverySupplement: "recent-subreddit-feed"`; the one-off `OUTPUT` target records whether the supplement was checked and how many matching candidates were found. The check covers only a recent feed page and can miss posts; it does not guarantee adult-content coverage. This option is off by default. Monitoring cannot combine it with `allowIncompleteMonitorFallback: false`; use a new monitor name when changing the option.

#### Optional incomplete fallback for subreddit listings

For a newest-first subreddit run, if the regular listing is refused or temporarily unavailable, the Actor may try Reddit's app feed. App results can miss or reorder posts, so rows carry `discoveryComplete: false` and the `OUTPUT` record reports a partial result. If the listing was refused and the app feed is unavailable without a rate limit, the Actor may try the matching public feed. This recovery does not translate an existing listing cursor or switch sources after a rate limit. Monitoring preserves the last complete checkpoint, and skips this recovery when `allowIncompleteMonitorFallback` is false. For a one-off run, `allowPartialSubredditFallback: true` also permits a Hot fallback for certain newest-listing failures; Hot results are sorted by creation time and can miss posts. The option is off by default and does not apply to keyword searches.

If the normal New or Rising sources fail without a rate limit, the Actor may also try a public web listing for a named subreddit. It checks each post against current Reddit data, but the listing may miss or reorder posts; rows are marked `discoverySource: "web-subreddit-partial"` and `discoveryComplete: false`. This route uses a residential connection and can add cost and latency. It does not apply to `r/all`, `r/popular`, existing listing cursors, or monitors with `allowIncompleteMonitorFallback: false`. Other monitors preserve the last complete checkpoint. A rate limit stops recovery.

If a named subreddit's Hot listing fails without a rate limit, the Actor may try an incomplete Hot feed. Posts are checked against current Reddit data, but the feed can miss or reorder them; rows are marked `discoverySource: "graphql-subreddit-partial"` and `discoveryComplete: false`. The fallback can add requests and latency. It does not apply to `r/all`, `r/popular`, existing listing cursors, or monitors with `allowIncompleteMonitorFallback: false`. Other monitors preserve their last complete checkpoint. A rate limit stops recovery.

For requests above 200 posts, incomplete subreddit app feeds can follow more pages, up to a maximum of 50. Larger requests take longer and may stop before reaching the requested count if a page limit, deadline, or rate limit is reached. Check `OUTPUT` for the run's status; these feeds remain incomplete even when they return the requested count.

For a one-off export of one named subreddit, set `captureResumeToken: true` and `sort` to `"new"` or `"rising"` to use the incomplete app feed with continuation support. Keep comments and monitoring off. If the run reaches its result or page limit, or an interruption occurs, the target in `OUTPUT.targets` may contain a `resumeToken` when a resumable position is known and prior rows are confirmed saved. To continue, run the same subreddit, sort, and filters with that value in `resumeToken`. A failed run can still have an `OUTPUT` record. A token is not guaranteed for every interruption or spending limit. If a post cannot be verified, the export can stop at that post and retries can stop there again. Reddit cursors can expire, the feed can change, and repeated or missing posts are possible; deduplicate across runs by post `id`. Results remain partial.

To use the incomplete app feed directly for New or Rising listings, including `r/all` and `r/popular`, set `preferIncompleteSubreddit: true`. It may miss or reorder posts, and its rows are marked `discoveryComplete: false`. All and Popular results use `discoverySource: "graphql-reddit-feed-partial"`. For monitoring, alerts and the last complete checkpoint follow the incomplete-monitor behavior above, and this option cannot be combined with `allowIncompleteMonitorFallback: false`. The option is off by default, does not affect other sorts or keyword searches, and cannot use a listing URL's existing cursor. A rate limit does not trigger another source.

To use a public web feed directly for New or Rising subreddit listings, set `preferWebSubreddit: true`. This source may miss or reorder posts; its results are checked against current post data and marked `discoverySource: "web-subreddit-partial"` and `discoveryComplete: false`. It does not cover keyword searches or other sorts. For monitoring, the last complete checkpoint is preserved, and this option cannot be combined with `allowIncompleteMonitorFallback: false`. Do not combine this option with `preferIncompleteSubreddit` or a listing URL's existing cursor. A rate limit does not trigger another source.

If a Rising listing is refused, a one-off run may use Reddit's app Rising feed first. Those results can miss or reorder posts and carry `discoveryComplete: false` with `discoverySource: "graphql-subreddit-partial"` or `"graphql-reddit-feed-partial"`. If that source fails without a rate limit, the Actor may return Hot posts instead, marked `hot-listing-partial`; Hot uses a different ranking. Existing listing cursors are not translated. Persistent monitoring preserves the last complete checkpoint, and skips these alternatives when `allowIncompleteMonitorFallback` is false. A rate limit stops the request.

#### Post and comment extraction

```json
{
  "postUrls": [
    "https://www.reddit.com/r/programming/comments/POST_ID/example/"
  ],
  "includeComments": true,
  "maxCommentsPerPost": 50,
  "maxCommentDepth": 3
}
```

### Output fields

Every post row includes:

- identity: `id`, `title`, `url`, `permalink`, `sourceQuery`
- author/community: `author`, `subreddit`, `flair`
- content: `selftext`, `post_hint`, `domain`, `mediaUrl`, `thumbnail`, `gallery_images`
- engagement: `score`, `upvoteRatio`, `numComments`, `gildingCount`
- flags: `isNSFW`, `is_spoiler`, `is_stickied`, `is_self`, `is_video`, `is_crosspost`, `is_locked`, `is_archived`
- timestamps: `created`, `scrapedAt`
- monitoring: `changeType`, `firstSeenAt` when `monitorMode` is `new-posts`
- partial fallback: `discoverySource`, `discoveryComplete` when an incomplete discovery source is used
- keyword search: `detailLevel: "search_result"`. Reddit's search results show each post's title, author, community, score, comment count and time, so these rows leave `selftext`, `upvoteRatio`, `flair` and the link destination empty, and `url` is the post's own Reddit link. Subreddit listings, user pages and exact post URLs include the full fields.
- optional comments: `topComments[]`, plus `commentsSource`, `commentDepthFilterApplied` and `commentTreeComplete` when comments are requested. `commentTreeComplete` is false if the tree is limited, incomplete or cannot be verified. Feed comments include `id`, `author`, `body`, and `permalink`; fields the feed does not provide are `null` or empty.

#### Example result

```json
{
  "id": "1uxtv30",
  "title": "New Python type checker",
  "author": "TheSeriousTrader",
  "subreddit": "Python",
  "url": "https://www.reddit.com/r/Python/comments/1uxtv30/new_python_type_checker/",
  "permalink": "https://www.reddit.com/r/Python/comments/1uxtv30/new_python_type_checker/",
  "selftext": "Was checking out some Python type checkers...",
  "score": 42,
  "upvoteRatio": 0.88,
  "numComments": 16,
  "created": "2026-07-16T05:39:00+00:00",
  "flair": "Discussion",
  "is_self": true,
  "topComments": []
}
```

### What you're charged for

A run has a start charge, and each unique post written to the dataset has a result charge. Comments included in a post do not add a result charge. An empty or failed run can still incur the start charge. See the Pricing tab on this Actor's Store page for current rates and details.

### Reliability and responsible use

- For one-off runs, check the run's `OUTPUT` key-value record for `resultStatus` (`complete`, `partial`, `failed`, or `limited`) and per-target `status` and `resultCount`. A run can save useful rows even when another target fails. An `unavailable` target could not be accessed; a `not_processed` target was not attempted. When Reddit rate-limits a target, its entry includes `failureReason: "rate_limited"`; a rate-limited session can instead report that reason at the top level before targets are attempted. If the run approaches its time limit while retrieving a page, verified posts may be saved as partial and the target can report `failureReason: "deadline"`. An unverifiable creation time with `newerThan` can report `failureReason: "timestamp_unavailable"`. `complete` means the Actor finished the requested target window; it does not guarantee Reddit returned every matching post. Some failures before target processing may not have this summary.
- A valid empty response from an incomplete source can finish the run with `resultStatus: "partial"`, zero rows, and a target `incompleteReason: "source_may_omit_results"`. This does not establish that no matching posts exist. Actual rate limits, invalid responses and deadline failures are not counted as valid empty responses.
- Across all inputs, each run supports up to 50 listing targets and 100 exact post URLs. Extra targets in a one-off run are listed as `not_processed` in `OUTPUT`; split them into another run. A monitor exceeding either combined limit stops before updating its state; split the watch into smaller monitors.
- If the comment-enabled post cap or spending limit reduces a one-off listing's requested maximum, its `OUTPUT` entry includes `requestedMaxResults`, `appliedMaxResults`, and `limitReason`. When the lower limit is reached and more posts may be available, the target is marked partial.
- A Reddit URL is sent to the right kind of target whichever input holds it, and Reddit app share links are followed to their post. A URL that cannot be used is skipped and listed as `unsupported` in `OUTPUT` while the valid targets continue; the run fails only when no input can be used. A non-Reddit URL in `queries` or `postUrls` is rejected when the run starts, before any charge.
- The default run time limit is 20 minutes. Large requests may still return fewer posts when Reddit limits access, the time limit is reached, or fewer matches are available. Check the `OUTPUT` record for the run's status.
- If comment retrieval reaches the run's cleanup reserve, the Actor keeps the verified post and marks its comments unavailable and incomplete. Other interruptions can still prevent output from being saved.
- The Actor collects public Reddit content only. Private, banned, quarantined, removed, or login-only content is unavailable.
- Requests are globally rate-limited with bounded retries for `429`, authorization refreshes, timeouts, and transient network failures.
- A persistent monitor raises a new-post alert only for posts created since its previous check, with a six-hour allowance. An older post that appears for the first time is recorded without an alert and counted as `olderPostsNotAlerted` in `OUTPUT`.
- Persistent monitors keep at most 50,000 post identities. The oldest identities can eventually age out of extremely high-volume watches.
- Monitoring visits every configured target but buffers at most 2,000 current post observations before diffing. With large watchlists, the Actor lowers `maxResults` evenly per listing; split broader cohorts into separate Tasks.
- A target that fails keeps its last checkpoint, so a failed page or deadline cannot corrupt the baseline. With `allowIncompleteMonitorFallback: false`, state updates only after every configured target completes.
- Reddit scores and comment counts can change between requests and may be hidden for very new posts.
- Comment-enabled listing runs are capped at 100 posts total across all queries; exact `postUrls` reuse their detail response and remain separate.
- The Actor first tries Reddit's current comment tree. `commentsSource: "graphql-comment-tree"` rows include available comment scores, parent IDs and depths. It can expand up to three collapsed branches per post and 30 per run, subject to the run deadline. `commentTreeComplete` is false when comments were excluded by the requested depth or count, or when the initial response reports more or collapsed comments, even if some branches were expanded. If the app tree fails and the direct web page is blocked or temporarily unavailable, it may try a public web page through a proxy connection; this can omit or reorder comments. When at least five requested comments are still missing, the web fallback can follow up to three top-level continuation pages per post, sharing the 30-request per-run continuation limit. Other sources cannot establish a complete tree, so also report false. Web and feed fallbacks omit blank text and removal placeholders; this can also omit media-only comments. Web comments have unknown award and controversiality fields. When a public feed is used, comments have unknown scores, parent IDs and reply depths, and `commentDepthFilterApplied` is `false`; `maxCommentDepth` cannot be enforced. Other `commentsSource` values are `public-feed`, `comment-tree`, and `unavailable`.
- Reddit has announced that RSS feed support ends on November 13, 2026. Search, newest-listing and comment feed fallbacks may stop working after that date.
- Search relevance and geographic availability are controlled by Reddit.
- If Reddit blocks the regular search endpoint, one-off keyword searches and monitors may use Reddit's app search before the search feed. Those rows carry `discoverySource: "graphql-search-partial"` and `discoveryComplete: false`: results can omit posts, including adult content, or differ from the normal search in order. Check the run's `OUTPUT` record for a partial result status. If app search cannot handle the input, the Actor may try the search feed. A rate limit stops the search rather than triggering a source switch. Persistent monitors skip app search when `allowIncompleteMonitorFallback` is false, and otherwise preserve their last complete checkpoint. It does not substitute for newest-first subreddit listings.
- If Reddit asks the Actor to pause partway through a search page, a one-off run can return the posts already verified. These rows have `discoveryComplete: false`; comments may be unavailable. Persistent monitors deliver those verified posts and keep their last complete checkpoint.
- Runs may pause once and retry when Reddit supplies a reset time: up to 6 seconds for fewer than five potential posts, 35 seconds for five to nine, or one minute for ten or more. Runs can still return partial results or fail if the limit continues.

### Workflows and guides

- [Scrape Reddit for community research](https://thirdwatch.dev/blog/scrape-reddit-for-community-research)
- [Monitor subreddits for B2B buyer signals](https://thirdwatch.dev/blog/monitor-subreddits-for-b2b-buyer-signals)
- [Track Reddit discourse on product launches](https://thirdwatch.dev/blog/track-reddit-discourse-on-product-launches)

Pairs well with [Twitter/X Scraper](https://apify.com/thirdwatch/twitter-scraper), [Google News Scraper](https://apify.com/thirdwatch/google-news-scraper), and [YouTube Scraper](https://apify.com/thirdwatch/youtube-scraper) for cross-channel listening.

### Input parameters

| Parameter | Required | Description |
|---|---:|---|
| `queries` | No | Plain text searches all Reddit. Use r/python for a subreddit listing or r/python: asyncio for search within one subreddit. r/python+golang runs each community separately, and they share `maxResults`. |
| `startUrls` | No | Existing public Reddit URLs. Subreddit/search pages are paginated; post URLs are extracted directly. |
| `postUrls` | No | Fetch exact public Reddit posts and, optionally, their comment threads. Accepts post links, `redd.it` short links, and Reddit app share links. |
| `sort` | No | How subreddit and search results are ordered. |
| `timeFilter` | No | Time range for top and relevance searches. |
| `maxResults` | No | Maximum unique posts returned for each query or listing URL. Pagination is automatic in batches of up to 100. Persistent monitors distribute a 2,000-observation safety budget across listing targets. |
| `includeComments` | No | Embed public comments in each post row. Feed comments have limited metadata. Comment-enabled listing runs are capped at 100 posts total. |
| `maxCommentsPerPost` | No | Maximum public comments embedded in each post row when comments are enabled. |
| `maxCommentDepth` | No | Maximum reply depth when the full comment tree is available. The public feed cannot be filtered by depth. |
| `minScore` | No | Only write posts at or above this visible Reddit score. |
| `skipPinnedPosts` | No | Exclude moderator-pinned or stickied posts from results. |
| `newerThan` | No | A date, a timestamp, or an age for one-off incremental exports, for example 2026-07-01, 2026-07-01T00:00:00Z, or 7 days. Persistent monitors usually leave this empty. |
| `monitorMode` | No | Return every current post, or persist a baseline and return only posts not seen by this watch. An unchanged new-posts run writes no billable result rows. |
| `allowIncompleteMonitorFallback` | No | On by default. Keeps a monitor running on an incomplete keyword or New, Rising, or named-subreddit Hot source when the regular source is unavailable. Alerts and the `OUTPUT` record identify affected runs; posts can be missed. Set to false to require complete data. |
| `captureResumeToken` | No | Enable resumable one-off New or Rising exports for one named subreddit, without comments. The feed remains incomplete. |
| `resumeToken` | No | Continue from a token returned in a previous run's `OUTPUT`, using the same subreddit, sort, and filters. |
| `monitorStoreName` | No | Stable identity for one scheduled watch. Reuse the same name and input on every run; use a different name for each independent monitor. |
| `allowPartialSubredditFallback` | No | Allow an additional incomplete Hot-page recovery for one-off newest-first subreddit listings. Not used for monitoring or keyword search. |
| `preferWebSubreddit` | No | Use the incomplete web feed directly for New or Rising subreddit listings. Persistent watches cannot combine it with `allowIncompleteMonitorFallback: false`. |
| `maxConcurrency` | No | Parallel parsing tasks for bodies/comments. Actual Reddit requests remain globally rate-limited. |
| `requestDelaySecs` | No | Minimum delay between anonymous Reddit API requests. Keep at 0.65 seconds unless you need a gentler crawl. |

### Use cases

- Marketers monitoring social presence and engagement
- Researchers building social-media datasets
- Teams tracking public figures and trends

### Limitations

- Comment-enabled listing runs are capped at 100 posts total across all queries, to respect Reddit and the run timeout; disable `includeComments` for larger post-only pulls.
- Persistent monitors distribute a 2,000-observation safety budget across listing targets, so very broad watch configurations can be throttled before every target is checked.
- Deleted, removed, or private-subreddit content disappears from results between runs, since the Actor reflects whatever Reddit currently serves publicly.
- `maxCommentsPerPost` limits comment count. `maxCommentDepth` applies only when `commentDepthFilterApplied` is `true`.
- Listing URLs that page backwards with `before` are not supported; use the URL without it.

Last verified: 2026-11-10

# Actor input Schema

## `queries` (type: `array`):

Plain text searches all Reddit. Use r/python for a subreddit listing or r/python: asyncio for search within one subreddit. r/python+golang runs each community separately, and they share Max results. Across all inputs, a run supports up to 50 listing targets.

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

Existing public Reddit URLs. A URL that cannot be used is skipped and listed in OUTPUT. Across all inputs, a run supports up to 50 listing targets and 100 exact post URLs.

## `postUrls` (type: `array`):

Fetch exact public Reddit posts and, optionally, their comment threads. Accepts post links, redd.it short links, and Reddit app share links. The limit is 100 exact post URLs across all inputs.

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

How subreddit and search results are ordered.

## `timeFilter` (type: `string`):

Time range for top and relevance searches.

## `maxResults` (type: `integer`):

Maximum unique posts returned for each query or listing URL. Pagination is automatic in batches of up to 100. Persistent monitors distribute a 2,000-observation safety budget across listing targets.

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

Embed public comments in each post row. Check commentsSource, commentDepthFilterApplied, and commentTreeComplete for coverage. Feed results omit scores and reply depth. Comment-enabled listings are capped at 100 posts total.

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

Maximum public comments embedded in each post row when comments are enabled.

## `maxCommentDepth` (type: `integer`):

Maximum reply depth when the full comment tree is available. Feed results cannot be filtered by depth and have commentDepthFilterApplied set to false.

## `minScore` (type: `integer`):

Only write posts at or above this visible Reddit score, including exact post URLs. Defaults to 0; set a negative value to include negative scores.

## `skipPinnedPosts` (type: `boolean`):

Exclude moderator-pinned or stickied posts, including exact post URLs.

## `newerThan` (type: `string`):

A date, a timestamp, or an age for listings and exact post URLs, for example 2026-07-01, 2026-07-01T00:00:00Z, or 7 days. Posts with unverifiable creation times are omitted and the target is incomplete. Persistent monitors usually leave this empty.

## `monitorMode` (type: `string`):

Return every current post, or persist a baseline and return only posts not seen by this watch. An unchanged new-posts run writes no billable result rows.

## `monitorStoreName` (type: `string`):

Stable identity for one scheduled watch. Reuse the same name and input on every run; use a different name for each independent monitor.

## `allowIncompleteMonitorFallback` (type: `boolean`):

On by default. When keyword search or a New, Rising, or Hot subreddit listing is unavailable, use an incomplete alternative that can miss posts or use different ordering. Hot recovery is limited to named subreddits. New-post alerts on these sources only cover recently created posts. Alerts are marked monitoringComplete=false; check OUTPUT for incomplete targets. The last complete checkpoint is preserved. Turn off to stop a run instead whenever a target is incomplete.

## `preferIncompleteSearch` (type: `boolean`):

Use an alternative for keyword search without trying the regular search source first. It can miss posts; rows are marked discoveryComplete=false. For monitoring, also enable Allow incomplete monitoring fallback. Off by default; does not change subreddit listings.

## `includeAdultSearchSupplement` (type: `boolean`):

For single-word searches within a named subreddit, with sort New and time filter All, also check up to 25 recent posts for literal title or body matches. Uses incomplete app search, can miss posts, and adds requests that may be rate-limited. For monitoring, enable Allow incomplete monitoring fallback. Off by default.

## `preferIncompleteSubreddit` (type: `boolean`):

Use an alternative directly for New or Rising subreddit listings, including r/all and r/popular. It can miss or reorder posts; rows are marked discoveryComplete=false. For monitoring, also enable Allow incomplete monitoring fallback. Off by default; does not affect keyword searches or other sorts.

## `captureResumeToken` (type: `boolean`):

For one named subreddit with New or Rising sort, without comments or monitoring, use an incomplete app feed and save a continuation in OUTPUT when a resumable position is available. Results may be missing or repeated. Off by default.

## `resumeToken` (type: `string`):

Paste a resumeToken from a previous run's OUTPUT. Use the same subreddit, sort, and filters; comments and monitoring must remain off. Reddit cursors may expire and results may be missing or repeated.

## `preferWebSubreddit` (type: `boolean`):

Use a public web feed directly for New or Rising subreddit listings. It can miss or reorder posts; rows are marked discoveryComplete=false. For monitoring, also enable Allow incomplete monitoring fallback. Off by default; does not affect keyword searches or other sorts.

## `allowPartialSubredditFallback` (type: `boolean`):

Allow an additional Hot-page recovery if a newest-first subreddit listing fails. It can miss posts; rows are marked discoveryComplete=false. Does not apply to keyword searches or monitoring.

## `maxConcurrency` (type: `integer`):

Parallel parsing tasks for bodies/comments. Actual Reddit requests remain globally rate-limited.

## `requestDelaySecs` (type: `number`):

Minimum delay between anonymous Reddit API requests. Keep at 0.65 seconds unless you need a gentler crawl.

## Actor input object example

```json
{
  "queries": [
    "r/programming",
    "AI agents"
  ],
  "startUrls": [],
  "postUrls": [],
  "sort": "hot",
  "timeFilter": "all",
  "maxResults": 10,
  "includeComments": false,
  "maxCommentsPerPost": 10,
  "maxCommentDepth": 1,
  "minScore": 0,
  "skipPinnedPosts": false,
  "monitorMode": "all",
  "allowIncompleteMonitorFallback": true,
  "preferIncompleteSearch": false,
  "includeAdultSearchSupplement": false,
  "preferIncompleteSubreddit": false,
  "captureResumeToken": false,
  "preferWebSubreddit": false,
  "allowPartialSubredditFallback": false,
  "maxConcurrency": 3,
  "requestDelaySecs": 0.65
}
```

# Actor output Schema

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

No description

# 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 = {
    "queries": [
        "r/programming",
        "AI agents"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("thirdwatch/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 = { "queries": [
        "r/programming",
        "AI agents",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("thirdwatch/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 '{
  "queries": [
    "r/programming",
    "AI agents"
  ]
}' |
apify call thirdwatch/reddit-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thirdwatch/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/rVyDJsbG80Y2j5sHa/builds/Ank9omKfREPMQlbWe/openapi.json
