Reddit Scraper avatar

Reddit Scraper

Pricing

from $4.00 / 1,000 results

Go to Apify Store
Reddit Scraper

Reddit Scraper

Scrape Reddit posts, comments, users, no login or API key. Search or paste URLs, filter by keyword/date, export to JSON/CSV/Excel or push to Notion, Slack & more.

Pricing

from $4.00 / 1,000 results

Rating

0.0

(0)

Developer

Techforce Global

Techforce Global

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

10 days ago

Last modified

Share

Reddit Scraper

Apify Actor MCP Ready Pricing Output Public data only Target

No Reddit app, no OAuth, no API credentials. Subreddits, posts, search terms, hashtag-style queries, user profiles and community lists in — four record types out in a single dataset: posts, comments, users and communities, each flat, typed and joinable. Built for social listening, market research and community analysis, with optional delivery into Notion, Slack, Linear, Jira, GitHub or Airtable over MCP.

🔐 Trust & compliance at a glance

CredentialsNone required. No Reddit account, app registration or OAuth token. Delivery runs through the Apify MCP Proxy, so the Actor never sees your connector tokens.
Data scopePublic content only — public subreddits, posts, comment threads and profiles. No login, no private or quarantined-with-login content, no direct messages.
⚠️ Personal dataReddit content is personal data. author, authorId, username and free-text body identify pseudonymous individuals, and profile rows carry karma and account history.
Reduce your exposureskipComments: true drops the largest source of user speech; maxComments: 0 does the same. Both keep post-level metrics intact.
NSFW controlincludeNSFW defaults to true — set it false to filter 18+ items out of the dataset.

Full detail, including GDPR position and Reddit's Terms: Compliance & Data Privacy.


Official Reddit Data API vs. Reddit Scraper Actor

Reddit's own API is a real alternative — with a registration and rate-limit story that stops many projects before they start:

Feature / CapabilityOfficial Reddit Data APIReddit Scraper Actor (Apify)
Setup❌ Register an app, obtain a client ID/secret, implement OAuth✅ Apify account, nothing else
Rate limits⚠️ Per-client request limits you must implement backoff for✅ Proxy rotation and retries handled for you
Commercial / high-volume use⚠️ Requires a separate paid agreement with Reddit✅ Standard Apify usage billing
Mixed entities in one run❌ Separate endpoints, separate pagination, your own glue code✅ Posts, comments, users and communities in one dataset
Search + subreddit + user in one job❌ You orchestrate it✅ Mix startUrls and searches freely
Filtering (keyword, date, NSFW)❌ Client-side, your code✅ Built into the input
AI agent / MCP native❌ Requires a custom tool wrapper✅ Native MCP tool and pushes results into your own MCP connectors
Officially sanctioned✅ Yes⚠️ No — see Compliance

Reddit's registration requirements, rate limits and commercial-use terms are Reddit's to change — check Reddit's current API terms if this comparison is load-bearing for your decision.


🤖 AI Discovery & MCP Metadata

Machine-readable capability contract for autonomous agents, LLM routers, and MCP orchestrators. Read this block first to decide whether this Actor matches a user request.

ai_discovery:
slug: "techforce.global/reddit-scraper"
one_line: >
Scrapes Reddit posts, comments, users and communities from subreddit URLs, post URLs, user
profiles, search result pages or plain search terms - no Reddit account, app registration or
OAuth. Four record types in one dataset, with keyword, date and NSFW filtering, media
extraction, and optional delivery into Notion, Slack, Linear, Airtable or any MCP connector.
primary_purpose: "extract"
secondary_purpose: "deliver"
entity: "Reddit post, comment, user and community"
category: "social-media / social-listening / market-research / community-analysis"
supported_platforms: ["reddit.com"]
supported_tasks:
- "scrape-a-subreddits-posts"
- "scrape-a-posts-comment-thread"
- "search-reddit-by-keyword"
- "find-subreddits-by-topic"
- "find-users-by-name"
- "scrape-a-user-profile-and-their-history"
- "filter-by-keyword-date-or-nsfw"
- "extract-post-media-urls"
- "deliver-results-to-mcp-connector"
unsupported_tasks:
- "scrape-private-quarantined-or-login-gated-content"
- "scrape-direct-messages-or-modmail"
- "post-comment-vote-or-any-write-action"
- "scrape-deleted-or-removed-content"
- "native-comment-search (comment search is approximated - see comment_search_is_approximated)"
- "download-media-files (URLs are extracted, files are not fetched)"
- "non-reddit-platforms"
search_keywords:
# First entry is the H1 / meta-description target. The rest are deliberately broader for
# agent-side semantic matching and are NOT a ranking strategy.
- "reddit scraper"
- "reddit api alternative"
- "scrape reddit comments"
- "subreddit data extraction"
- "reddit post scraper no api key"
- "social listening reddit"
- "reddit sentiment analysis data"
- "reddit user profile scraper"
- "subreddit discovery tool"
- "mcp reddit tool"
input_entities:
- "startUrls (subreddit, post, user, search or community-list URLs)"
- "searches (plain keywords)"
- "searchType (posts | comments | communities | users)"
- "sort / time / commentSort"
- "maxItems (GLOBAL cap across the run, 0 = unlimited)"
- "maxPostCount / maxComments / maxCommentDepth / maxCommunitiesCount / maxUserCount"
- "skipComments / skipUserPosts / skipCommunityInfo"
- "includeNSFW / keywords / postDateFrom / postDateTo"
- "extractMedia / dedupItems"
- "proxyConfiguration / maxConcurrency / maxRequestRetries / debugMode"
no_input_field_is_required_by_the_schema: >
CRITICAL: nothing is marked required. A run with neither startUrls nor searches passes
validation, logs "No valid start URLs or search terms provided. Exiting." and ends SUCCEEDED
with an empty dataset. Supply at least one of startUrls or searches.
output_is_four_record_types: >
CRITICAL: one dataset holds four shapes, discriminated by the `type` field - "post",
"comment", "user" and "community". Always branch on `type` before reading a row. Fields that
do not apply to a type are absent, not null.
output_entities_post: ["type", "id", "parsedId", "subreddit", "subredditId", "title", "body",
"author", "authorId", "url", "link", "domain", "flair", "createdAt", "createdTimestamp",
"score", "upVotes", "upvoteRatio", "numberOfComments", "numberOfCrossposts", "awardsCount",
"isSelf", "isVideo", "isOriginalContent", "over18", "spoiler", "locked", "stickied",
"distinguished", "media"]
output_entities_comment: ["type", "id", "parsedId", "subreddit", "body", "author", "authorId",
"url", "parentId", "postId", "createdAt", "createdTimestamp", "score", "upVotes", "depth",
"isSubmitter", "stickied", "controversiality", "distinguished", "numberOfReplies",
"postTitle", "postUrl"]
output_entities_user: ["type", "id", "parsedId", "username", "url", "createdAt",
"createdTimestamp", "linkKarma", "commentKarma", "totalKarma", "awardeeKarma", "awarderKarma",
"isGold", "isMod", "isEmployee", "verified", "hasVerifiedEmail", "iconImage", "description",
"over18"]
output_entities_community: ["type", "id", "parsedId", "name", "title", "url", "description",
"longDescription", "createdAt", "createdTimestamp", "numberOfMembers", "activeUsers",
"over18", "type_", "lang", "category", "iconImage", "bannerImage"]
max_items_is_global_and_counts_comments: >
maxItems (default 100) is a hard cap on TOTAL dataset items for the whole run, and comments
count toward it. With comments on, a maxItems of 100 is typically consumed by the comments of
the first few posts. Raise maxItems, or set skipComments true, when you want post breadth.
comment_search_is_approximated: >
searchType "comments" does NOT run a native Reddit comment search. It searches POSTS for the
term and then scrapes those posts' comment threads, so the comments returned are from matching
posts, not comments that themselves match the term. Use the keywords filter if you need the
term to appear in the comment text.
sort_falls_back_per_source: >
sort is validated per source type. On subreddit listings only hot/new/top/rising/controversial
/best are valid - "relevance" and "comments" fall back to "hot". On searches only relevance/
hot/top/new/comments are valid - "rising" falls back to "relevance". time only applies to
top/controversial listings and to searches.
comment_depth_is_zero_based: >
maxCommentDepth 1 returns top-level comments only; 3 returns depth 0, 1 and 2; 0 is unlimited.
The depth field on a comment row is 0-based.
filters_are_post_fetch: >
includeNSFW, keywords, postDateFrom and postDateTo are applied AFTER an item is fetched. They
shrink the dataset, not the number of requests, so they do not reduce run cost much.
personal_data_present: >
author, authorId, username and free-text body are personal data about pseudonymous
individuals under GDPR/UK GDPR and CCPA-CPRA. skipComments true (or maxComments 0) removes the
largest volume of user speech while keeping post-level metrics.
browser_based_run: >
Requests are rendered through a real headless browser so Reddit serves data instead of a bot
wall, with an automatic second retrieval path when the first is challenged. That makes runs
slower and more resource-hungry than a plain HTML scraper - size maxItems accordingly.
known_limitations:
deleted_content: "[deleted] / [removed] bodies are returned as Reddit serves them"
score_is_fuzzed: "Reddit fuzzes vote counts; score and upVotes are approximate"
comment_completeness: "'more comments' placeholders are not expanded - deep threads are partial"
post_title_only_from_posts: "postTitle/postUrl exist only on comments scraped via their post"
media_urls_only: "media holds URLs; no files are downloaded"
snapshot_only: "scores, karma and member counts are true as of the run"
free_plan_capped: "free Apify plans stop at 25 items TOTAL per run"
pricing:
model: "usage-based"
billing_unit: "Apify platform usage consumed by the run"
hard_ceiling_parameter: "maxTotalChargeUsd"
note: "Browser-driven, so cost per item is higher than an HTML-only scraper. Current rates are on the Actor's Apify Store page."
when_to_use: >
You want Reddit discussion as structured data - a subreddit's posts, a thread's comments,
topic search across Reddit, subreddit discovery, or a user's public history - without
registering a Reddit app.
when_not_to_use: >
You need private, quarantined or login-gated content, deleted content, direct messages, native
comment search, downloaded media files, or to post/vote/interact.
mcp_delivery:
modes: ["perItem", "summary", "none"]
default: "perItem"
per_item_is_the_default: >
Unlike most Actors, deliveryMode defaults to perItem - one connector call per scraped item.
Set "summary" or "none" unless you really want a record per post/comment/user/community.
per_item_safety_cap: 1000
per_item_placeholders: "every field of the item, plus aliases {title}, {text}, {permalink}, and {message}"
summary_placeholders: ["{itemCount}", "{postCount}", "{commentCount}", "{userCount}", "{communityCount}", "{items}", "{message}"]
never_blocks_the_dataset: >
Delivery runs after the crawl, reading the dataset back. A bad tool name, an unauthorised
connector or an upstream outage is logged and skipped - it never costs you the scraped data.
alternatives:
- "techforce.global/facebook-public-comments for public Facebook page comment threads"
- "techforce.global/youtube-scraper for YouTube video, channel and comment data"
- "techforce.global/advanced-website-crawling-actor for whole-site text, Markdown or HTML"

{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Reddit Scraper – Posts, Comments, Users & Communities",
"alternateName": "Reddit API Alternative",
"applicationCategory": "BusinessApplication",
"operatingSystem": "Cloud (Apify platform)",
"description": "Scrapes Reddit posts, comments, users and communities from subreddit URLs, post URLs, user profiles, search pages or plain keywords — without a Reddit account, app registration or OAuth. Returns four record types in a single dataset, each discriminated by a type field: posts with score, upvote ratio, flair and media URLs; comments with depth, parent and reply counts; users with karma breakdowns; and communities with member and active-user counts. Includes keyword, date and NSFW filtering, in-run deduplication, media URL extraction, proxy rotation, and optional delivery into Notion, Slack, Linear, Airtable or any MCP connector.",
"url": "https://apify.com/techforce.global/reddit-scraper",
"offers": {
"@type": "Offer",
"priceCurrency": "USD",
"category": "Pay per platform usage",
"description": "Usage-based: billed for the compute time and resources a run consumes, not per row. Runs are browser-driven, so cost per item is higher than an HTML-only scraper. Current rates are shown on the Actor's Apify Store page."
}
}

What this Actor does

  • Six kinds of input, mixed freely in one run. Subreddit URLs (with or without a sort tab), post permalinks, user profiles, in-subreddit or global search pages, community lists — plus plain keywords via searches. No Reddit app, no OAuth, no credentials.

  • Four record types in one dataset. post, comment, user and community, each flat and discriminated by type. Comments carry postId and parentId, so a thread rebuilds exactly.

  • Whole-entity coverage, not just the headline object. A subreddit URL also yields the community's about record; a user profile also yields that user's public history — each switchable off with skipCommunityInfo / skipUserPosts.

  • Real filtering, in the input. Keyword match, postDateFrom / postDateTo (absolute dates or relative strings like 7 days), and an NSFW switch — applied to every item before it reaches your dataset.

  • Media URLs extracted for you. Thumbnails, preview images, Reddit-hosted video, gallery images and the external link a post points at, in one nested media object.

  • Deduplicated within the run. The same post reached from a search and from its subreddit is written once (dedupItems, on by default).

  • Gets past the bot wall. Requests render through a real headless browser, with an automatic second retrieval path when the first is challenged, and a fresh proxy session on rate-limit retries.

  • Saves as it goes and stops cleanly. Items are written as they are parsed and the platform ABORTING event is handled, so an aborted or capped run keeps everything collected so far.

  • Optionally delivers into your tools. Notion, Slack, Linear, Jira, GitHub, Airtable or anything else you've authorised.


When to use it — and when not to

ScenarioFit
Every recent post in a subreddit✅ Strong — a subreddit URL, or several
A specific thread's full comment tree✅ Strong — a post permalink, maxCommentDepth to taste
Topic search across Reddit✅ Strong — searches + searchType: "posts"
Finding subreddits about a topic✅ Strong — searchType: "communities"
A user's public posting history✅ Strong — a /user/... URL
Community size and activity metrics✅ Strong — numberOfMembers, activeUsers
Social listening / sentiment corpora✅ Strong — comment bodies with scores and depth
Post-level metrics without user speech✅ Strong — skipComments: true
Keyword, date or NSFW filtering✅ Strong — built into the input
Results in Notion / Slack / Airtable✅ Strong — native MCP delivery
Comments that themselves match a keyword⚠️ searchType: "comments" searches posts, then scrapes their comments — add a keywords filter
A complete deep comment tree⚠️ "More comments" placeholders aren't expanded — deep threads come back partial
Exact vote counts⚠️ Reddit fuzzes scores; treat them as approximate
Private, quarantined or login-gated content❌ Public content only
Deleted or removed content❌ Returned only as Reddit serves it ([deleted] / [removed])
Direct messages or modmail❌ Never accessible
Downloading images or video files❌ URLs are extracted; files are not fetched
Posting, commenting, voting, moderating❌ Read-only
Non-Reddit platforms❌ Reddit only

⚡ Execution Rules (Avoid Common Agent Failures)

  1. Supply at least one of startUrls or searches. Nothing is marked required in the schema, so a run with neither passes validation, logs No valid start URLs or search terms provided. Exiting. and ends SUCCEEDED with an empty dataset. Never read itemCount: 0 as a crash.

  2. maxItems is a GLOBAL cap and comments count toward it. Default 100. With comments on, the first two or three posts' threads can consume the whole budget before the fourth post is reached. For post breadth, either raise maxItems or set skipComments: true.

  3. Branch on type before reading any row. One dataset, four shapes — post, comment, user, community. Fields that don't apply to a type are absent, not null, so use .get() / optional access.

  4. searchType: "comments" is an approximation. It searches posts for your term and then scrapes those posts' comments — the comments themselves are not matched against the term. If you need the term to appear in the comment text, add it to the keywords filter as well.

  5. sort is validated per source and silently falls back. On subreddit listings, relevance and comments are not valid sorts and become hot. On searches, rising is not valid and becomes relevance. time only applies to top / controversial listings and to searches.

  6. maxCommentDepth is 0-based in the output. 1 = top-level only, 3 = depth 0, 1 and 2, 0 = unlimited.

  7. The per-source caps stack under maxItems. maxPostCount (per subreddit / search / user), maxComments (per post), maxCommunitiesCount and maxUserCount (per source) all bound their own scope — but maxItems still ends the run first when it is reached.

  8. Filters run after fetching. includeNSFW, keywords, postDateFrom and postDateTo shrink the dataset, not the request count — they are not a cost-control lever.

  9. includeNSFW defaults to true. Set it false if 18+ content must not enter your dataset.

  10. A subreddit URL yields a community row too, and a user URL yields the user's history — unless you set skipCommunityInfo / skipUserPosts.

  11. postTitle and postUrl only appear on comments scraped through their post. Comments collected from a user's history don't carry them — join on postId instead.

  12. Keep the proxy enabled. Default is {"useApifyProxy": true}. Reddit rate-limits by IP; on larger runs prefer residential. A 429 is retried on a fresh session up to maxRequestRetries (default 5).

  13. This Actor drives a real browser. It is slower and more resource-hungry per item than an HTML-only scraper, and maxConcurrency (default 10) ramps up from a low starting point on purpose. Lower it if you're being rate-limited.

  14. deliveryMode defaults to perItem — one connector call per scraped item, capped at 1,000 deliveries with a warning. Set summary or none unless you want a record each.

  15. Free Apify plans stop at 25 items total per run — not per source.

dependencies:
- rule: "at least one of startUrls / searches must be non-empty"
on_violation: "run ends SUCCEEDED with an empty dataset and a warning in the log - it does NOT fail validation"
- rule: "maxItems bounds the whole run, including comments"
note: "set skipComments true when you want many posts rather than deep threads"
- rule: "delivery requires mcpConnector AND mcpTool"
on_violation: "delivery is skipped with a warning; every dataset row is still written"
- rule: "mcpArguments must reference {message} for the rendered template to appear anywhere"
on_violation: "message body is empty; the tool is still called"
- rule: "mcpConnector only resolves when the Actor runs on the Apify platform"
on_violation: "local runs log 'APIFY_MCP_PROXY_URL is not set' and skip delivery"
authentication:
actor_input: none
platform: "Apify API token required for API / SDK / MCP invocation"
target_site: "no Reddit account, app registration or OAuth token required (public content only)"

📥 Input Contract

.actor/input_schema.json is authoritative — if this page disagrees with the schema files, the schema files win.

Sources

ParameterTypeRequiredDefaultNotes
startUrlsarraysee noteSubreddit, post, user, search or community-list URLs
searchesarray<string>see notePlain keywords; each runs one search
searchTypestring (enum)⬜ Nopostsposts · comments · communities · users

At least one of startUrls or searches must be non-empty. Nothing is required in the schema, so this is enforced at runtime.

Accepted startUrls shapes:

ShapeExampleWhat you get
Subreddithttps://www.reddit.com/r/technology/community row + its posts (+ comments)
Subreddit with sorthttps://www.reddit.com/r/technology/top/?t=weekThe sort and time window in the URL win over sort/time
In-subreddit searchhttps://www.reddit.com/r/technology/search?q=aiMatching posts from that subreddit
Post permalinkhttps://www.reddit.com/r/x/comments/abc123/slug/The post + its comment tree
User profilehttps://www.reddit.com/user/spez/user row + their public history
User sub-page.../user/spez/submitted · /comments · /overviewJust that slice of their history
Global search pagehttps://www.reddit.com/search?q=bitcoinMatching posts
Community listhttps://www.reddit.com/subreddits/search?q=aiMatching community rows

An unrecognised URL is skipped with Could not classify URL, skipping: <url> in the log.

Sorting

ParameterTypeDefaultValid where
sortstring (enum)newrelevance · hot · top · new · rising · comments. Listings accept hot/new/top/rising (others → hot); searches accept relevance/hot/top/new/comments (risingrelevance)
timestring (enum)allhour · day · week · month · year · all. Applies to top/controversial listings and to searches
commentSortstring (enum)topconfidence (Best) · top · new · controversial · old · qa

Limits

ParameterTypeDefaultScope
maxItemsinteger100Whole run, all types, comments included. 0 = unlimited
maxPostCountinteger50Per subreddit / search / user. 0 = unlimited
maxCommentsinteger20Per post. 0 = skip comments entirely
maxCommentDepthinteger31 = top-level only, 0 = unlimited (depth is 0-based)
maxCommunitiesCountinteger10Per source. 0 = unlimited
maxUserCountinteger10Per source. 0 = unlimited

Content toggles and filters

ParameterTypeDefaultEffect
skipCommentsbooleanfalseNo comment rows — faster, cheaper, far less personal data
skipUserPostsbooleanfalseFor user URLs, return only the profile row
skipCommunityInfobooleanfalseFor subreddit URLs, skip the community about-row
includeNSFWbooleantruefalse drops items flagged over18
keywordsarray<string>[]Keep only items whose title/body/description contains one of these (case-insensitive)
postDateFromstring""YYYY-MM-DD, DD/MM/YYYY, an ISO datetime, or relative — 7 days, 3 months, 1 year
postDateTostring""Same formats; a bare date includes the whole day
extractMediabooleantruePopulate the media object on posts
dedupItemsbooleantrueDrop repeats of the same type + id within the run

Filters are applied after an item is fetched — they shrink the dataset, not the request count.

Runtime

ParameterTypeDefaultNotes
proxyConfigurationobject{"useApifyProxy": true}Leave enabled. Reddit rate-limits by IP; residential is best for larger runs
maxConcurrencyinteger10150. Browser-driven, so it ramps from a low start. Lower it if rate-limited
maxRequestRetriesinteger5Retries a blocked or rate-limited request on a fresh session
debugModebooleanfalseVerbose logging

Delivery (optional)

ParameterTypeDefaultDescription
mcpConnectorstring""A connector you've authorised on your Apify account — Notion, Slack, Linear, Jira, GitHub, Airtable, or any MCP-compatible connector. Leave empty for dataset-only runs.
deliveryModestring (enum)perItemperItem (one call per item, capped at 1,000) · summary (one digest call) · none.
mcpToolstring""Tool to call — create_page, send_message, create_issue. Required when a connector is set; run once and the log lists the connector's tools.
mcpArgumentsobject{}Arguments for the tool. String leaves support {placeholder} tokens.
mcpMessageTemplatestring""Template rendered and exposed to mcpArguments as {message}.

Placeholders by mode:

ModePlaceholders
perItemevery field of the item{type} {id} {author} {subreddit} {score} {url} {createdAt} … — plus the cross-type aliases {title}, {text}, {permalink} and {message}. Nested values (like media) arrive JSON-encoded; nulls render empty.
summary{itemCount} {postCount} {commentCount} {userCount} {communityCount} {items} (a formatted digest, truncated at ~60,000 characters) {message}

The aliases exist because the four types don't share field names: {title} resolves to a post's title, a community's name or a username; {text} to a comment body, a post body or a description. Use them for templates that must work across every type.


📤 Output Contract & Data Structure

One dataset, four record types. Branch on type first. Fields that don't apply to a type are absent keys, not nulls.

Shared by every type

FieldTypeMeaning
typestringpost · comment · user · communityread this first
idstringReddit's base-36 ID for the entity. The join/dedup key
parsedIdstringReddit's fullname (t3_…, t1_…, t2_…, t5_…)
urlstringCanonical reddit.com URL for the entity
createdAtstringISO-8601 UTC
createdTimestampintegerEpoch seconds — use this for arithmetic

type: "post"

FieldTypeMeaning
subreddit / subredditIdstringCommunity the post is in
titlestringPost title
bodystringSelf-text; "" for link posts
author / authorIdstringPersonal data. [deleted] when the account is gone
link / domainstringWhere a link post points, and its domain
flairstringLink flair text
score / upVotesintegerFuzzed by Reddit — approximate
upvoteRationumber0–1
numberOfCommentsintegerReddit's count — not the number of comment rows scraped
numberOfCrossposts / awardsCountintegerCrossposts and awards
isSelf / isVideo / isOriginalContentbooleanPost format flags
over18 / spoiler / locked / stickiedbooleanContent and state flags
distinguishedstringmoderator / admin when applicable
mediaobject{thumbnail, images[], video, gallery[], externalLink} — only when extractMedia

type: "comment"

FieldTypeMeaning
subredditstringCommunity the comment is in
bodystringComment text. Personal data. [deleted]/[removed] as Reddit serves it
author / authorIdstringPersonal data
parentIdstringt1_… (a comment) or t3_… (the post) — rebuilds the tree
postIdstringt3_… fullname of the post — join key
depthinteger0-based nesting level
score / upVotesintegerApproximate
isSubmitterbooleantrue when the commenter is the post's author
stickied / controversiality / distinguishedmixedModeration and state signals
numberOfRepliesintegerDirect replies present in the payload
postTitle / postUrlstringOnly on comments scraped through their post — absent for comments from a user's history

type: "user"

FieldTypeMeaning
usernamestringPersonal data — the pseudonymous identity
linkKarma / commentKarma / totalKarmaintegerKarma breakdown
awardeeKarma / awarderKarmaintegerAward karma
isGold / isMod / isEmployee / verified / hasVerifiedEmailbooleanAccount flags
iconImagestringAvatar URL
descriptionstringProfile blurb
over18booleanProfile marked 18+

type: "community"

FieldTypeMeaning
namestringSubreddit name without r/
titlestringDisplay title
description / longDescriptionstringShort blurb and full sidebar text
numberOfMembersintegerSubscribers
activeUsersintegerUsers online at capture time
over18boolean18+ community
type_stringpublic / restricted / private … (note the trailing underscore)
lang / categorystringDeclared language and advertiser category
iconImage / bannerImagestringCommunity imagery

Example output — one of each type

[
{
"type": "post",
"id": "1abcxyz",
"parsedId": "t3_1abcxyz",
"subreddit": "technology",
"title": "Our team open-sourced the ingestion pipeline behind the launch",
"body": "Writing up what broke and what we'd do differently…",
"author": "some_builder",
"authorId": "t2_9q1w2",
"url": "https://www.reddit.com/r/technology/comments/1abcxyz/our_team_open_sourced/",
"link": "https://github.com/example/pipeline",
"domain": "github.com",
"flair": "Software",
"createdAt": "2026-08-19T14:03:11+00:00",
"createdTimestamp": 1787148191,
"score": 3184,
"upVotes": 3184,
"upvoteRatio": 0.94,
"numberOfComments": 412,
"isSelf": false,
"over18": false,
"locked": false,
"media": {
"thumbnail": "https://b.thumbs.redditmedia.com/…jpg",
"images": ["https://preview.redd.it/…png"],
"video": null,
"gallery": [],
"externalLink": "https://github.com/example/pipeline"
}
},
{
"type": "comment",
"id": "kx91mno",
"parsedId": "t1_kx91mno",
"subreddit": "technology",
"body": "The backpressure section is the part everyone skips and then regrets.",
"author": "queue_nerd",
"authorId": "t2_4d5f6",
"url": "https://www.reddit.com/r/technology/comments/1abcxyz/…/kx91mno/",
"parentId": "t3_1abcxyz",
"postId": "t3_1abcxyz",
"createdAt": "2026-08-19T15:22:40+00:00",
"createdTimestamp": 1787152960,
"score": 214,
"depth": 0,
"isSubmitter": false,
"numberOfReplies": 3,
"postTitle": "Our team open-sourced the ingestion pipeline behind the launch",
"postUrl": "https://www.reddit.com/r/technology/comments/1abcxyz/our_team_open_sourced/"
},
{
"type": "user",
"id": "9q1w2",
"parsedId": "t2_9q1w2",
"username": "some_builder",
"url": "https://www.reddit.com/user/some_builder",
"createdAt": "2017-03-04T09:11:02+00:00",
"createdTimestamp": 1488618662,
"linkKarma": 12045,
"commentKarma": 38210,
"totalKarma": 50255,
"isMod": false,
"verified": true,
"description": "Backend engineer. Opinions my own."
},
{
"type": "community",
"id": "2qh16",
"parsedId": "t5_2qh16",
"name": "technology",
"title": "Technology",
"url": "https://www.reddit.com/r/technology/",
"description": "Subreddit dedicated to the news and discussions about technology.",
"createdAt": "2008-01-25T05:15:47+00:00",
"createdTimestamp": 1201238147,
"numberOfMembers": 18400000,
"activeUsers": 4123,
"over18": false,
"type_": "public",
"lang": "en"
}
]

Values illustrate shape and formatting — the posts, people and numbers are invented.

What a successful run looks like

  • Status: SUCCEEDED
  • Dataset: interleaved post, comment, user and community rows, in crawl order
  • Log: Starting with N seed request(s). Item cap: …, then a line per listing, post and profile, then Crawl finished.
  • Zero results is also a success. No sources supplied, an unclassifiable URL, a private or banned subreddit, or a bot-block all return an empty dataset with SUCCEEDED. Check the log.
  • Hitting maxItems ends the run early and cleanly — that's the cap doing its job, not a failure.

Dataset views

ViewShows
OverviewType, title/body, author, subreddit, score, comments, date — everything in one table
PostsTitle, author, subreddit, score, upvote ratio, comments, flair, links
CommentsBody, author, subreddit, score, depth, submitter flag, replies, parent post
CommunitiesName, members, active users, description, 18+ flag
UsersUsername, karma breakdown, verified and mod flags
Post MediaTitle, subreddit, self/video flags, the media object, link and domain

▶️ Invocation & Integration

Authenticate every call with Authorization: Bearer <APIFY_TOKEN>.

Apify Console

Open the Actor pageInput tab → paste subreddit/post/user URLs and/or type search terms → set maxItems and the per-source caps → decide whether you want comments → leave the proxy on → Start.

Model Context Protocol (MCP)

claude mcp add --transport http apify \
"https://mcp.apify.com?tools=techforce.global/reddit-scraper"

Then ask your agent for "what r/technology is saying about this launch".

Python (apify-client)

import os
from collections import Counter
from apify_client import ApifyClient
client = ApifyClient(os.getenv("APIFY_TOKEN"))
run = client.actor("techforce.global/reddit-scraper").call(run_input={
"startUrls": [{"url": "https://www.reddit.com/r/technology/top/?t=week"}],
"maxItems": 500,
"maxPostCount": 50,
"maxComments": 20,
"maxCommentDepth": 3,
"deliveryMode": "none",
"proxyConfiguration": {"useApifyProxy": True},
})
rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())
if not rows:
raise SystemExit("Nothing scraped — check the run log (no sources? blocked?).")
print(Counter(r["type"] for r in rows)) # e.g. Counter({'comment': 420, 'post': 50, 'community': 1})
# ALWAYS branch on type — one dataset, four shapes.
posts = [r for r in rows if r["type"] == "post"]
comments = [r for r in rows if r["type"] == "comment"]
# Rebuild each thread: comments join to posts on postId -> parsedId.
by_post = {p["parsedId"]: {"post": p, "comments": []} for p in posts}
for c in comments:
thread = by_post.get(c.get("postId"))
if thread:
thread["comments"].append(c)
for thread in sorted(by_post.values(), key=lambda t: t["post"].get("score") or 0, reverse=True)[:5]:
p = thread["post"]
# numberOfComments is Reddit's figure; len(...) is what we actually scraped.
print(f'{p["score"]:>6} {len(thread["comments"])}/{p.get("numberOfComments")} {p["title"][:60]}')

JavaScript / TypeScript (apify-client)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('techforce.global/reddit-scraper').call({
searches: ['vector database'],
searchType: 'posts',
sort: 'top',
time: 'month',
maxItems: 300,
skipComments: false,
maxComments: 25,
keywords: ['pgvector', 'qdrant', 'weaviate'], // post-fetch filter
deliveryMode: 'none',
proxyConfiguration: { useApifyProxy: true },
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
// Four record types — split before you touch any field.
const byType = items.reduce<Record<string, any[]>>((acc, i) => {
(acc[i.type] ??= []).push(i);
return acc;
}, {});
console.log(Object.entries(byType).map(([t, v]) => `${t}: ${v.length}`).join(', '));
// Top-level comments only (depth is 0-based).
for (const c of (byType.comment ?? []).filter((c) => c.depth === 0).slice(0, 10)) {
console.log(`[r/${c.subreddit}] u/${c.author} (${c.score}): ${c.body.slice(0, 100)}`);
}

cURL — synchronous (waits, returns the dataset)

curl -X POST \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
-d '{
"startUrls": [{ "url": "https://www.reddit.com/r/AskReddit/" }],
"maxItems": 50,
"skipComments": true,
"deliveryMode": "none",
"proxyConfiguration": { "useApifyProxy": true }
}' \
'https://api.apify.com/v2/acts/techforce.global~reddit-scraper/run-sync-get-dataset-items'
# 1. Start with a hard spend limit
curl -X POST -H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
-d '{ "searches": ["bitcoin"], "maxItems": 2000, "maxComments": 50,
"proxyConfiguration": { "useApifyProxy": true } }' \
'https://api.apify.com/v2/acts/techforce.global~reddit-scraper/runs?maxTotalChargeUsd=10'
# 2. Poll, then 3. fetch the dataset when SUCCEEDED
curl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' 'https://api.apify.com/v2/actor-runs/<runId>'
curl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
'https://api.apify.com/v2/datasets/<DATASET_ID>/items?clean=true&format=json'

Posts only, no comments — the cheap, low-risk configuration

{
"startUrls": [{ "url": "https://www.reddit.com/r/technology/" }],
"maxItems": 200,
"maxPostCount": 200,
"skipComments": true,
"extractMedia": false,
"deliveryMode": "none",
"proxyConfiguration": { "useApifyProxy": true }
}

Post-level metrics with no comment rows: far fewer items per post, a much smaller dataset, and no user speech in your output. Start here.

One thread, deep — for sentiment analysis

{
"startUrls": [{ "url": "https://www.reddit.com/r/technology/comments/1abcxyz/some_thread/" }],
"maxItems": 1000,
"maxComments": 500,
"maxCommentDepth": 0,
"commentSort": "top",
"deliveryMode": "none",
"proxyConfiguration": { "useApifyProxy": true }
}

maxCommentDepth: 0 follows every reply level the payload contains. Note that "more comments" placeholders are not expanded, so very large threads still come back partial.

Topic monitoring on a schedule

{
"searches": ["our product name"],
"searchType": "posts",
"sort": "new",
"postDateFrom": "7 days",
"maxItems": 300,
"maxComments": 20,
"includeNSFW": false,
"deliveryMode": "none",
"proxyConfiguration": { "useApifyProxy": true }
}

Put a fixed input on a schedule, keep postDateFrom relative so the window moves with each run, and dedupe against your store on id.

With MCP delivery — a digest into Slack

{
"searches": ["our product name"],
"maxItems": 200,
"proxyConfiguration": { "useApifyProxy": true },
"mcpConnector": "<your-authorized-slack-connector>",
"mcpTool": "send_message",
"deliveryMode": "summary",
"mcpMessageTemplate": "Reddit: {postCount} posts, {commentCount} comments\n\n{items}",
"mcpArguments": { "channel": "#social-listening", "text": "{message}" }
}

Use summary deliberatelyperItem is the default and would post one Slack message per scraped row.


⚠️ Autonomous Agent Error Handling & Resolution Matrix

Read this first: almost nothing fails the run. Missing sources, an unclassifiable URL, a blocked request and an empty subreddit all end SUCCEEDED while the log carries the reason. An agent that checks run status alone will read an empty dataset as success-with-data — check the row count and the log.

The CONDITION labels are documentation handles for observable states; this Actor writes no error code into the dataset.

ConditionWhat you observeCauseDeterministic agent action
NO_SOURCES_PROVIDEDSUCCEEDED, empty dataset; log: No valid start URLs or search terms provided. Exiting.Both startUrls and searches empty — not caught by validationModify Input: supply at least one source.
URL_NOT_CLASSIFIEDThat URL contributes nothing; log: Could not classify URL, skipping: <url>Not a recognised Reddit URL shapeModify Input: use one of the shapes in the Input Contract.
BOT_WALL_OR_BLOCKEDEmpty/thin dataset; log: Could not obtain JSON from … Reddit may be blocking this requestProxy disabled, or the IP is blockedModify Input: enable Apify Proxy, prefer residential, lower maxConcurrency.
RATE_LIMITED_BY_REDDITLog: Rate limited by Reddit (HTTP 429) - retrying with a new session/proxy.Too many requests from one IPExpected, self-healing. If it repeats, lower maxConcurrency to 23.
PRIVATE_OR_BANNED_SUBREDDITNo rows for that subredditPrivate, banned or quarantined communityDo not retry. Public content only.
MAX_ITEMS_TRUNCATED_RUNFewer posts than expected; comments dominatemaxItems is global and comments count toward itModify Input: raise maxItems, or set skipComments: true.
TYPE_MISMATCH_IN_CONSUMERConsumer crashes reading title / bodyOne dataset, four shapesFix consumer: branch on type, use .get().
COMMENT_SEARCH_MISMATCHsearchType: "comments" returned comments that don't mention the termIt searches posts, then scrapes their commentsModify Input: add the term to keywords as well.
SORT_IGNOREDResults aren't in the order you asked forrelevance/comments are search-only (→ hot); rising is listing-only (→ relevance)Fix expectation or pick a sort valid for that source.
TIME_IGNOREDtime had no effectIt only applies to top/controversial listings and searchesModify Input: set sort: "top".
DEPTH_OFF_BY_ONEFewer reply levels than expecteddepth is 0-based; maxCommentDepth: 3 yields depths 0–2Fix expectation, or raise the value / use 0.
PARTIAL_DEEP_THREADBig thread came back incomplete"More comments" placeholders are not expandedExpected. Raise maxComments; full expansion isn't supported.
FILTERS_DIDNT_CUT_COSTSmall dataset, unchanged run timeFilters are applied after fetchingFix expectation: use the caps to control cost, not filters.
NO_MEDIA_OBJECTmedia missing on postsextractMedia: falseModify Input: enable it.
MISSING_POST_TITLE_ON_COMMENTpostTitle/postUrl absentThat comment came from a user's history, not from its postFix consumer: join on postId → the post's parsedId.
SCORES_DONT_MATCH_REDDITScores differ slightly from the siteReddit fuzzes vote countsExpected. Treat scores as approximate.
DUPLICATES_EXPECTED_BUT_ABSENTFewer rows than sources suggestdedupItems is on by defaultExpected. Set it false to keep repeats.
FREE_PLAN_CAPPED25 items; log: Free plan detected - capping this run to 25 items.Free Apify plan — the cap is totalUpgrade the plan.
CONNECTOR_CALL_STORMHundreds of connector callsdeliveryMode defaults to perItem (capped at 1,000, with a warning)Modify Input: switch to summary or none.
CONNECTOR_TOOL_NOT_FOUNDLog: Tool 'x' is not available on this connector. Available tools: …Wrong mcpTool name (empty is logged separately)Modify Input: copy an exact name from that log line. Dataset unaffected.
CONNECTOR_UNREACHABLELog: Could not reach the connector: … or APIFY_MCP_PROXY_URL is not setConnector not authorised, or running locallyAuthorise it, or apify push and run on the platform. Data already saved.
AUTH_INVALIDHTTP 401Missing or malformed APIFY_TOKENAbort & prompt user for a valid token.
RATE_LIMITED_APIFYHTTP 429Apify API rate / concurrency limits — not RedditRetry: exponential backoff (2s, 4s, 8s).
SYNC_TIMEOUTHTTP 408 on the sync endpointRun exceeded the synchronous ceilingReconfigure: async POST /runs + polling.

Provenance: every log line, status and dataset condition above is taken from this Actor's own source and verified against it. The three HTTP rows describe the Apify API transport layer, not this Actor — confirm them against the Apify API reference before wiring them into automated retry logic.


🗣️ Natural Language → Actor Mapping

A user says…IntentConstructed Actor input
"What's on r/technology right now?"Subreddit listing{"startUrls":[{"url":"https://www.reddit.com/r/technology/"}],"sort":"hot"}
"Top posts in r/x this week"Ranked listing{"startUrls":[{"url":"https://www.reddit.com/r/x/top/?t=week"}]}
"Get every comment on this thread"Thread extraction{"startUrls":[{"url":"<permalink>"}],"maxComments":500,"maxCommentDepth":0,"maxItems":1000}
"What is Reddit saying about Topic search{"searches":["<topic>"],"searchType":"posts","sort":"new"}
"Which subreddits discuss Community discovery{"searches":["<topic>"],"searchType":"communities","maxCommunitiesCount":25}
"Find Reddit users called User search{"searches":["<name>"],"searchType":"users","maxUserCount":25}
"What has u/User history{"startUrls":[{"url":"https://www.reddit.com/user/<name>/"}]}
"Just their profile stats"Profile only{"startUrls":[{"url":"https://www.reddit.com/user/<name>/"}],"skipUserPosts":true}
"Mentions of us in the last week"Monitoring{"searches":["<brand>"],"postDateFrom":"7 days","sort":"new"}
"Posts only, no comments"Cheap/low-risk pull{"startUrls":[{"url":"<subreddit>"}],"skipComments":true}
"No adult content please"Safe corpusAdd {"includeNSFW":false}
"Only posts mentioning X or Y"Keyword filterAdd {"keywords":["X","Y"]}
"How big is r/x?"Community stats{"startUrls":[{"url":"https://www.reddit.com/r/x/"}],"maxPostCount":1} — read the community row
"Which of these are Shorts…" (wrong platform)➡️ Not Reddit; see the YouTube Actors
"Send new mentions to Slack"Scrape + deliverAbove, plus mcpConnector, mcpTool, deliveryMode: "summary"
"It returned nothing"Empty resultCheck a source was supplied, the URL shape is recognised, and the proxy is on
"Post this comment for me"Write action❌ Read-only — out of scope

Should NOT route here: private, quarantined or login-gated content · deleted or removed content · direct messages or modmail · posting, voting, or moderating · downloading media files (URLs only) · native comment search (comment search is approximated via posts) · non-Reddit platforms — for YouTube use the YouTube Scraper, for public Facebook page comments the Facebook Public Comment Tracker.


🧭 Agent Execution & Routing Logic

Does the user want PUBLIC REDDIT content as data?
├── NO → wrong Actor.
│ YouTube videos/comments → YouTube Scraper
│ Facebook page comments → Facebook Public Comment Tracker
│ a whole website's text → Advanced Website Crawling Actor
│ private/DM/mod content → not obtainable
└── YES
├── What do they actually have? (mix freely; at least ONE is mandatory at
│ runtime even though the schema marks nothing required)
│ ├── a community → startUrls: r/<sub> (+ a community row)
│ ├── a specific thread→ startUrls: permalink (most predictable cost)
│ ├── a person → startUrls: /user/<name> (+ their history)
│ ├── a topic → searches + searchType "posts"
│ ├── "which subs?" → searches + searchType "communities"
│ └── "which users?" → searches + searchType "users"
├── ALWAYS keep proxyConfiguration enabled (useApifyProxy: true)
├── Do they need COMMENTS?
│ ├── no → skipComments: true → fewer items, lower cost, NO user speech
│ └── yes → maxComments PER POST, maxCommentDepth (0-based; 0 = unlimited)
│ └── remember: comments count toward the GLOBAL maxItems
├── Size the run
│ ├── maxItems → GLOBAL cap, comments included (0 = unlimited)
│ ├── maxPostCount → per subreddit / search / user
│ └── big run? → set maxTotalChargeUsd as well
├── Narrow the output (post-fetch — these do NOT cut cost)
│ ├── keywords → term must appear in title/body/description
│ ├── postDateFrom → "7 days" / "2026-01-01"
│ └── includeNSFW → false to drop 18+ items
├── What is the actual question?
│ ├── what's popular → sort top/hot, read score + upvoteRatio
│ ├── what's new → sort new + postDateFrom
│ ├── how do they feel→ comment bodies, join on postId
│ ├── where to engage → searchType "communities", read numberOfMembers/activeUsers
│ └── who is talking → user rows + karma
└── Should results land in another app?
├── yes → mcpConnector + mcpTool + {message} in mcpArguments
│ digest → summary · record each → perItem (DEFAULT; capped at 1000)
└── no → deliveryMode "none", or leave mcpConnector empty
[Execute Actor]
├──► SUCCEEDED with rows → split by `type`, then consume
├──► SUCCEEDED, 0 rows → READ THE LOG: no source / unclassified URL / blocked / private
└──► exactly 25 rows → free plan cap, not a data pull

💰 Cost Control & Pricing Transparency

Billing model: usage-based. This Actor bills for platform usage — the compute time and resources a run consumes — not per row. Current rates are on the Actor's Apify Store page; the Console shows the live total mid-run.

It is browser-driven, which is what gets past Reddit's bot wall — and also what makes each request heavier than a plain HTML fetch. Size runs accordingly.

ChoiceEffect on cost
maxItemsThe main lever — a hard stop on the whole run, comments included.
skipComments / maxCommentsThe second lever. One extra request per post, and comment rows dominate item counts.
Number of sourcesEach subreddit, search and user is its own paginated crawl.
maxPostCountPagination depth per source — more pages, more requests.
maxCommentDepthDeeper trees mean bigger payloads, not more requests.
maxConcurrencyFaster when Reddit tolerates it; rate-limit retries make it slower.
Filters (keywords, dates, NSFW)No meaningful cost saving — applied after fetching.
Being blockedCosts run time and returns nothing. A disabled proxy is the most expensive setting on this page.

Worked examples — relative run shape

ScenarioRequests (approx.)ItemsNotes
Probe — 1 subreddit, maxItems: 25, comments off1 listing + 1 about≤ 26Baseline. Confirms proxy and URL shape.
Subreddit sweep — 200 posts, comments off~3 listing pages~201Cheapest per item.
Same 200 posts with maxComments: 20~3 listings + 200 post fetchesup to ~4,200~200× the requests — this is the expensive switch.
One thread, maxComments: 500, depth 01 fetch≤ 501Best value per comment; a single payload.
Topic search, 50 posts, comments off~1 search page~50Predictable.
Community discovery, 25 subreddits~1 search page~25Very cheap.
Brand monitor — search + 20 comments/post, 300 itemssearch pages + ~15 post fetches300 (capped)maxItems stops it precisely.
Unbounded — maxItems: 0 on a busy subredditunboundedunboundedNever without maxTotalChargeUsd.

Keeping runs predictable:

  1. First run: one source, maxItems: 25, skipComments: true.
  2. Decide the comment question up front — comments multiply both requests and rows, and they are the part that carries personal data.
  3. Prefer permalinks for comment-heavy work — one post URL is one predictable fetch; a subreddit sweep with comments is one fetch per post.
  4. Use the caps, not the filters, to control cost.
  5. Always set maxTotalChargeUsd when maxItems is 0 or in the thousands.
  6. Free Apify plans get 25 items per run — a connectivity check, not a data pull.

🛠️ Troubleshooting

Most problems are missing sources, the proxy, the global maxItems cap, or the four-record-type shape — not scraper bugs.

#Symptom you seeMost likely causeFix
1SUCCEEDED but the dataset is emptyNeither startUrls nor searches supplied — the schema doesn't enforce itRead the log for No valid start URLs or search terms provided. and supply a source.
2A URL you pasted produced nothingIt wasn't recognised — log: Could not classify URL, skipping: …Use a documented URL shape (/r/…, /comments/…, /user/…, /search?q=…, /subreddits/search?q=…).
3Thin results, or Could not obtain JSON from … in the logReddit's bot wall or an IP blockKeep Apify Proxy on, prefer residential, and lower maxConcurrency to 23.
4Log repeats Rate limited by Reddit (HTTP 429)Too many requests from one IPSelf-healing via retries; if persistent, lower maxConcurrency and raise maxRequestRetries.
5Far fewer posts than expected, lots of commentsmaxItems is global and comments count toward itRaise maxItems, or set skipComments: true for post breadth.
6Consumer crashes on a missing fieldFour record types share one datasetBranch on type; use .get() — absent ≠ null.
7searchType: "comments" returned off-topic commentsIt searches posts, then scrapes their commentsAdd the term to keywords too, or accept post-level matching.
8Sort seems ignoredrelevance/comments are search-only (→ hot); rising is listing-only (→ relevance)Pick a sort valid for that source type.
9time had no effectIt only applies to top/controversial listings and searchesSet sort: "top" alongside it.
10Fewer reply levels than expecteddepth is 0-based — maxCommentDepth: 3 gives depths 0–2Raise it, or use 0 for unlimited.
11A big thread came back incomplete"More comments" placeholders aren't expandedRaise maxComments; full expansion isn't supported.
12Filters didn't make the run cheaperThey're applied after fetchingUse maxItems / maxPostCount / skipComments for cost.
13NSFW content in the datasetincludeNSFW defaults to trueSet it false.
14No media on postsextractMedia: false, or the post has noneEnable extractMedia; text posts legitimately have empty media.
15postTitle / postUrl missing on commentsThose comments came from a user's historyJoin on postId → the post's parsedId.
16Scores differ from what the site showsReddit fuzzes vote countsExpected — treat scores as approximate.
17numberOfComments ≫ the comment rows you gotThat's Reddit's count, not the scrape countCompare deliberately; raise maxComments if you need more.
18Duplicate posts across sourcesdedupItems is on by default — if you see repeats, they differ by idDedupe downstream on id, or check dedupItems.
19Exactly 25 rows came backFree plan cap — total, not per sourceUpgrade the plan; the log says Free plan detected….
20A private/banned subreddit returned nothingPublic content onlyNothing to fix — no scraper can reach it.
21Hundreds of connector calls fireddeliveryMode defaults to perItemSet summary or none. Delivery is capped at 1,000 calls with a warning.
22Slack / Notion received nothingDelivery needs both mcpConnector and mcpToolSet both. Every dataset row is still saved.
23Connector message fields are blankThe template used a field that record type lacksUse the cross-type aliases {title} / {text} / {permalink}, or branch on {type}.
24Log: APIFY_MCP_PROXY_URL is not setRan locally; connectors only resolve on the platformapify push and run on the platform.
25HTTP 401 / 403 from the Apify APIMissing, expired or malformed APIFY_TOKENRegenerate in Console → Settings → API & Integrations.
26HTTP 429 / 408 from the Apify APIApify rate limits / the sync endpoint's time ceilingBack off (2s → 4s → 8s), or switch to async POST /runs + polling.

Diagnostic checklist before opening an issue

  1. Confirm a source is setstartUrls or searches.
  2. Open the URL signed-out in a browser. Private, banned and quarantined communities look identical to a scraper.
  3. Confirm Apify Proxy is enabled, and try residential if you see bot-wall lines.
  4. Baseline run: one subreddit, maxItems: 25, skipComments: true, deliveryMode: "none".
  5. Count rows by type before concluding anything is missing.
  6. Turn on debugMode for a verbose log if the above doesn't explain it.

If the issue survives all six, open an Issues ticket (or email support) with the run ID, the input you used, and what you expected.


❓ FAQ

Do I need a Reddit account, app registration or API key?

No. The Actor reads publicly available Reddit content. You need an Apify account and API token; you need no Reddit credentials, client ID or OAuth token.

Is this the official Reddit API?

No. This is an independent Actor and is not affiliated with, endorsed by, or sponsored by Reddit, Inc.

Do I need to configure proxies?

Apify Proxy is on by default and you should leave it on — Reddit rate-limits by IP and blocks unfamiliar traffic. For larger runs, a residential group is the most reliable choice.

Can I plug it into Claude, Cursor, or a LangChain agent?

Yes — it is a native MCP tool: claude mcp add --transport http apify "https://mcp.apify.com?tools=techforce.global/reddit-scraper"

What can I put in startUrls?

Subreddit URLs (with or without a sort tab and ?t= window), post permalinks, user profiles and their /submitted, /comments or /overview sub-pages, global or in-subreddit search pages, and community-list URLs. Anything unrecognised is skipped with a log line.

Can I mix URLs and search terms in one run?

Yes. startUrls and searches are processed in the same run, and every item is written to the same dataset.

Why did I get so few posts and so many comments?

Because maxItems is a global cap on the whole run and comments count toward it. With the default of 100 and comments on, the first few threads can consume the entire budget. Raise maxItems, or set skipComments: true when you want post breadth.

How do I search comments specifically?

You can't, natively — and this is the one place the input name is optimistic. searchType: "comments" searches posts for your term and then scrapes those posts' comment threads, so the comments returned belong to matching posts rather than matching the term themselves. Add the term to the keywords filter if it must appear in the comment text.

Why does my sort seem to be ignored?

Because sorts are validated per source. Subreddit listings accept hot, new, top, rising (and controversial/best) — relevance and comments silently become hot. Searches accept relevance, hot, top, new, commentsrising becomes relevance. time only applies to top/controversial listings and to searches.

How does maxCommentDepth work?

Depth is 0-based: 1 returns top-level comments only, 3 returns depths 0, 1 and 2, and 0 is unlimited. Note that Reddit's "more comments" placeholders are not expanded, so very deep threads still come back partial.

Why do rows have different fields?

One dataset holds four record types — post, comment, user and community — discriminated by type. Fields that don't apply to a type are absent keys, not nulls, so branch on type and use optional access.

How do I rebuild a thread from the output?

Join comments to posts on postId → the post's parsedId (t3_…), then nest comments using parentId and order them by depth. postTitle/postUrl are also present on comments scraped through their post.

Do the scores match what I see on Reddit?

Approximately. Reddit deliberately fuzzes vote counts, so score and upVotes are close but not exact, and they are a snapshot as of the run.

Can I filter by keyword or date?

Yes — keywords, postDateFrom and postDateTo (absolute dates or relative strings like 7 days). They're applied after an item is fetched, so they shrink your dataset but don't reduce run cost.

Does it download images and videos?

No. The media object holds thumbnail, preview image, video, gallery and external-link URLs; the files themselves are never fetched.

Can it get deleted, private or quarantined content?

No. Deleted content comes back as Reddit serves it ([deleted] / [removed]), and private, banned or login-gated communities are inaccessible by design.

Which delivery mode should I use, and does it work locally?

summary for one digest of the whole run; perItemthe default — sends one connector call per scraped item and is capped at 1,000 with a warning; none for dataset-only runs. Delivery only works on the Apify platform; locally you'll see APIFY_MCP_PROXY_URL is not set and the dataset saves as normal.

Does the output contain personal data?

Yes. author, authorId, username and free-text body identify pseudonymous individuals, and user rows include karma and account age. skipComments: true removes the largest volume of it while keeping post-level metrics. Read Compliance & Data Privacy before storing or reusing it.

What does it cost, and what do I get on the free plan?

Usage-based: you pay for the platform usage a run consumes, not per row. Because it drives a real browser, cost per item is higher than an HTML-only scraper — maxItems and skipComments are your main levers. Free Apify plans return 25 items total per run. Pass maxTotalChargeUsd for a hard per-run ceiling.


🔍 Companion machine-readable files

FileWhat it defines
.actor/input_schema.jsonEvery input, its type, default, bounds and enums
.actor/dataset_schema.jsonAll 59 possible fields across the four record types, and the six Console views
.actor/output_schema.jsonWhere the run's output is exposed
.actor/actor.jsonActor identity and storage wiring

If this page and the schema files disagree, the schema files win. They are what the platform validates against at run time; this page is documentation and can lag a release.


ActorBest for
YouTube Scraper: Videos, Channels & CommentsThe same social-listening question on YouTube — video metadata, channel stats and comment threads
Facebook Public Comment TrackerComment threads under a public Facebook page's posts
Advanced Website Crawling ActorWhole-site text, Markdown or HTML for RAG and search
Pinterest ScraperPins from searches, boards, profiles and pin URLs
YouTube Full Channel Transcripts ScraperTranscripts of every video on a channel, for a text corpus

Pipeline patterns: brand monitoring — this Actor on a schedule with postDateFrom: "7 days", comments on, digest to Slack via MCP · cross-platform listening — Reddit + YouTube + Facebook comment corpora merged on your own topic keys · community targeting

searchType: "communities"
to size and rank subreddits before you engage · research corpus — one thread at full depth, comment bodies into your LLM for theme extraction.

Browse all Actors by Techforce Global at scraper.techforce.global.


🔐 Compliance & Data Privacy

Trademark & affiliation. This is an independent Actor. It is not affiliated with, endorsed by, or sponsored by Reddit, Inc. Reddit™ is a trademark of Reddit, Inc.; all trademarks are the property of their respective owners.

  • Public content only. Everything returned is visible to any signed-out visitor. No private, banned, quarantined or login-gated communities, no direct messages, no modmail, no credentials.

  • ⚠️ Reddit content is personal data. author, authorId, username and free-text body relate to identifiable — if pseudonymous — individuals, and profile rows add karma, account age and verification flags. Under GDPR / UK GDPR and CCPA/CPRA, pseudonymous data is still personal data, and the obligations sit with you, not with the Actor.

  • Reddit is unusually sensitive as a source. People post about health, addiction, sexuality, politics, immigration status and employment under a handle they believe is separable from their real name. Aggregating a user's history across subreddits — which a /user/ scrape does by design — is exactly the operation that can de-pseudonymise someone. Treat it as the high-risk processing it is, and don't do it casually.

  • The cheapest compliance measure is a single field. If your question is about topics rather than people, set skipComments: true. You keep post titles, scores, subreddit metrics and media, and you shed the bulk of the user speech.

  • Minimise, then aggregate. Sentiment scores, theme counts and engagement ratios rarely require keeping raw author / authorId columns. Drop them at ingest, keep retention short, and restrict access.

  • Special-category content can't be filtered in advance. You cannot know which threads contain it until after retrieval. includeNSFW: false removes 18+ flagged items but is not a sensitivity filter.

  • Deleted means deleted. If a user removes a post or comment after your run, your copy no longer reflects their choice. Re-scrape or expire your data rather than treating a snapshot as permanently valid.

  • Content is the authors' copyrighted expression. Internal research, analysis and reporting sit on far safer ground than republishing scraped posts and comments as your own content. Using Reddit content to train a model is a legally distinct act with its own contested position — take advice rather than relying on "it was public".

  • Reddit's Terms and API terms restrict automated access and commercial reuse. This Actor does not remove that risk — it is a risk you accept by running it. The official Data API is the sanctioned route.

  • Attribution over mirroring. Every row carries a url. Link back to the thread rather than presenting Reddit discussion as your own content, and never quote a pseudonymous user in a way that ties them to an identity they didn't publish.


🆘 Support & Custom Pipeline Engineering

Need automated multi-city scheduled feeds, webhook enrichment, or enterprise data warehouse syncs?



🏷️ Structured data for search & AI discovery

SoftwareApplication describes the Actor; FAQPage wraps the FAQ above so those answers are eligible for rich results, matching it question-for-question.

{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Reddit Scraper – Posts, Comments, Users & Communities",
"alternateName": "Reddit API Alternative",
"applicationCategory": "BusinessApplication",
"applicationSubCategory": "Web Scraping / Social Listening & Community Analysis",
"operatingSystem": "Cloud (Apify platform)",
"description": "Scrapes Reddit posts, comments, users and communities from subreddit URLs, post URLs, user profiles, search pages or plain keywords — without a Reddit account, app registration or OAuth. Returns four record types in a single dataset, each discriminated by a type field: posts with score, upvote ratio, flair and media URLs; comments with depth, parent and reply counts; users with karma breakdowns; and communities with member and active-user counts. Includes keyword, date and NSFW filtering, in-run deduplication, media URL extraction, proxy rotation, and optional delivery into Notion, Slack, Linear, Airtable or any MCP connector.",
"url": "https://apify.com/techforce.global/reddit-scraper",
"author": { "@type": "Organization", "name": "Techforce Global", "url": "https://www.techforceglobal.com" },
"provider": { "@type": "Organization", "name": "Apify", "url": "https://apify.com" },
"offers": {
"@type": "Offer",
"priceCurrency": "USD",
"category": "Pay per platform usage",
"description": "Usage-based: billed for the compute time and resources a run consumes, not per row. Runs are browser-driven, so cost per item is higher than an HTML-only scraper. Current rates are shown on the Actor's Apify Store page.",
"url": "https://apify.com/techforce.global/reddit-scraper"
},
"featureList": [
"No Reddit account, app registration or OAuth token required",
"Subreddit, post, user, search and community-list URLs plus plain keywords in one run",
"Four record types in one dataset, discriminated by a type field",
"Posts with score, upvote ratio, flair, crossposts and awards",
"Comment trees with depth, parentId, postId and reply counts",
"User profiles with full karma breakdown and account flags",
"Community records with member and active-user counts",
"Keyword, absolute-date and relative-date filtering, plus an NSFW switch",
"Media URL extraction: thumbnails, previews, video, galleries and external links",
"In-run deduplication on type and id",
"Global maxItems cap plus per-source and per-post limits",
"Proxy rotation with automatic retry on rate limits",
"Optional MCP delivery to Notion, Slack, Linear, Airtable and more",
"Six Console dataset views covering posts, comments, users, communities and media"
],
"isAccessibleForFree": false,
"softwareRequirements": "Apify account and API token",
"keywords": "Reddit scraper, Reddit API alternative, scrape Reddit comments, subreddit data extraction, social listening, sentiment analysis data, Reddit user profile scraper, subreddit discovery, market research, MCP connector"
}
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Do I need a Reddit account, app registration or API key?",
"acceptedAnswer": { "@type": "Answer", "text": "No. The Actor reads publicly available Reddit content. You need an Apify account and API token; you need no Reddit credentials, client ID or OAuth token." }
},
{
"@type": "Question",
"name": "Is this the official Reddit API?",
"acceptedAnswer": { "@type": "Answer", "text": "No. This is an independent Actor and is not affiliated with, endorsed by, or sponsored by Reddit, Inc." }
},
{
"@type": "Question",
"name": "Do I need to configure proxies?",
"acceptedAnswer": { "@type": "Answer", "text": "Apify Proxy is on by default and you should leave it on — Reddit rate-limits by IP and blocks unfamiliar traffic. For larger runs, a residential group is the most reliable choice." }
},
{
"@type": "Question",
"name": "Can I plug it into Claude, Cursor, or a LangChain agent?",
"acceptedAnswer": { "@type": "Answer", "text": "Yes — it is a native MCP tool: claude mcp add --transport http apify \"https://mcp.apify.com?tools=techforce.global/reddit-scraper\"" }
},
{
"@type": "Question",
"name": "What can I put in startUrls?",
"acceptedAnswer": { "@type": "Answer", "text": "Subreddit URLs (with or without a sort tab and ?t= window), post permalinks, user profiles and their /submitted, /comments or /overview sub-pages, global or in-subreddit search pages, and community-list URLs. Anything unrecognised is skipped with a log line." }
},
{
"@type": "Question",
"name": "Can I mix URLs and search terms in one run?",
"acceptedAnswer": { "@type": "Answer", "text": "Yes. startUrls and searches are processed in the same run, and every item is written to the same dataset." }
},
{
"@type": "Question",
"name": "Why did I get so few posts and so many comments?",
"acceptedAnswer": { "@type": "Answer", "text": "Because maxItems is a global cap on the whole run and comments count toward it. With the default of 100 and comments on, the first few threads can consume the entire budget. Raise maxItems, or set skipComments: true when you want post breadth." }
},
{
"@type": "Question",
"name": "How do I search comments specifically?",
"acceptedAnswer": { "@type": "Answer", "text": "You can't, natively. searchType \"comments\" searches posts for your term and then scrapes those posts' comment threads, so the comments returned belong to matching posts rather than matching the term themselves. Add the term to the keywords filter if it must appear in the comment text." }
},
{
"@type": "Question",
"name": "Why does my sort seem to be ignored?",
"acceptedAnswer": { "@type": "Answer", "text": "Sorts are validated per source. Subreddit listings accept hot, new, top, rising (and controversial/best) — relevance and comments silently become hot. Searches accept relevance, hot, top, new, comments — rising becomes relevance. time only applies to top/controversial listings and to searches." }
},
{
"@type": "Question",
"name": "How does maxCommentDepth work?",
"acceptedAnswer": { "@type": "Answer", "text": "Depth is 0-based: 1 returns top-level comments only, 3 returns depths 0, 1 and 2, and 0 is unlimited. Reddit's \"more comments\" placeholders are not expanded, so very deep threads still come back partial." }
},
{
"@type": "Question",
"name": "Why do rows have different fields?",
"acceptedAnswer": { "@type": "Answer", "text": "One dataset holds four record types — post, comment, user and community — discriminated by type. Fields that don't apply to a type are absent keys, not nulls, so branch on type and use optional access." }
},
{
"@type": "Question",
"name": "How do I rebuild a thread from the output?",
"acceptedAnswer": { "@type": "Answer", "text": "Join comments to posts on postId → the post's parsedId (t3_…), then nest comments using parentId and order them by depth. postTitle/postUrl are also present on comments scraped through their post." }
},
{
"@type": "Question",
"name": "Do the scores match what I see on Reddit?",
"acceptedAnswer": { "@type": "Answer", "text": "Approximately. Reddit deliberately fuzzes vote counts, so score and upVotes are close but not exact, and they are a snapshot as of the run." }
},
{
"@type": "Question",
"name": "Can I filter by keyword or date?",
"acceptedAnswer": { "@type": "Answer", "text": "Yes — keywords, postDateFrom and postDateTo (absolute dates or relative strings like 7 days). They're applied after an item is fetched, so they shrink your dataset but don't reduce run cost." }
},
{
"@type": "Question",
"name": "Does it download images and videos?",
"acceptedAnswer": { "@type": "Answer", "text": "No. The media object holds thumbnail, preview image, video, gallery and external-link URLs; the files themselves are never fetched." }
},
{
"@type": "Question",
"name": "Can it get deleted, private or quarantined content?",
"acceptedAnswer": { "@type": "Answer", "text": "No. Deleted content comes back as Reddit serves it ([deleted] / [removed]), and private, banned or login-gated communities are inaccessible by design." }
},
{
"@type": "Question",
"name": "Which delivery mode should I use, and does it work locally?",
"acceptedAnswer": { "@type": "Answer", "text": "summary for one digest of the whole run; perItem — the default — sends one connector call per scraped item and is capped at 1,000 with a warning; none for dataset-only runs. Delivery only works on the Apify platform; locally you'll see APIFY_MCP_PROXY_URL is not set and the dataset saves as normal." }
},
{
"@type": "Question",
"name": "Does the output contain personal data?",
"acceptedAnswer": { "@type": "Answer", "text": "Yes. author, authorId, username and free-text body identify pseudonymous individuals, and user rows include karma and account age. skipComments: true removes the largest volume of it while keeping post-level metrics. Read the Compliance & Data Privacy section before storing or reusing it." }
},
{
"@type": "Question",
"name": "What does it cost, and what do I get on the free plan?",
"acceptedAnswer": { "@type": "Answer", "text": "Usage-based: you pay for the platform usage a run consumes, not per row. Because it drives a real browser, cost per item is higher than an HTML-only scraper — maxItems and skipComments are your main levers. Free Apify plans return 25 items total per run. Pass maxTotalChargeUsd for a hard per-run ceiling." }
}
]
}