Subreddit Scraper — Reddit Posts, Comments & Search, No API Key avatar

Subreddit Scraper — Reddit Posts, Comments & Search, No API Key

Pricing

from $1.50 / 1,000 items

Go to Apify Store
Subreddit Scraper — Reddit Posts, Comments & Search, No API Key

Subreddit Scraper — Reddit Posts, Comments & Search, No API Key

Type a subreddit and get its posts as rows — title, text, score, upvote ratio, comment count, flair, date, image or playable video link — sorted hot, new, top or rising. Add comments per post, search all of Reddit, or paste post links. No API key, no login, exact limit.

Pricing

from $1.50 / 1,000 items

Rating

0.0

(0)

Developer

Steadyfetch Team

Steadyfetch Team

Maintained by Community

Actor stats

0

Bookmarked

7

Total users

4

Monthly active users

2 days ago

Last modified

Share

Reddit Scraper — Subreddit Posts, Comments & Search, No API Key

Click Start with nothing set and the run returns a small built-in sample — one public subreddit, five posts, comments off — so you see the output shape before you spend anything, at no result fee.

Using an AI agent? Pin this actor in Apify's MCP server with one link: https://mcp.apify.com?tools=steadyfetch/reddit-scraper

  • Actor id: steadyfetch/reddit-scraper
  • Input: { "subreddits": ["smallbusiness"] } — the one field to set. Or { "searchQueries": ["apify"] } to search all of Reddit, or { "postUrls": ["https://www.reddit.com/r/smallbusiness/comments/1wdl068/i_understand_why_my_supplier_doesnt_take_cards/"] } for posts you already have links to.
  • Cap the bill: set maxTotalChargeUsd on the run (a run option, not Actor input), e.g. 0.50 — the run stops when it reaches it.
  • Your cap is the cap. resultsLimit (default 50) is exact and per subreddit or query; maxItems (default 1,000) caps the whole run, post rows and comment rows together. If your input carries limit, count or maxPosts instead — the names other Reddit scrapers use — the smallest of them is read as maxItems and an uncharged note row says which. Another Reddit scraper's searches, timeFilter and time are read the same way, as searchQueries and timeframe, with an uncharged note row saying so.

Priced from $1.50 per 1,000 items on the cheapest paid tier, $3.00 per 1,000 on the Apify free plan, platform usage included, no start fee. One item is one row — a post, or a comment. You are charged when a row lands in your dataset, plus one flat $0.005 check per page read of a subreddit or search that turns up nothing new for you (see What it costs): a subreddit Reddit will not show us, a post link that is gone, a search that matched nothing, and every row a limit or the run clock stopped us from collecting all cost $0.

What one row looks like

A real delivered post row, built by this actor's own parser from a harvested subreddit listing:

{
"type": "post",
"id": "1wdl068",
"fullname": "t3_1wdl068",
"permalink": "https://www.reddit.com/r/smallbusiness/comments/1wdl068/i_understand_why_my_supplier_doesnt_take_cards/",
"subreddit": "smallbusiness",
"subredditId": "t5_2qr34",
"title": "I understand why my supplier doesn’t take cards but damn",
"text": "We're placing our biggest inventory order so far and I completely forgot this supplier is ACH only…",
"authorName": "…",
"authorId": "…",
"createdAt": "2026-09-11T16:24:41.000Z",
"score": 80,
"upvotes": 80,
"upvoteRatio": 0.92,
"commentCount": 46,
"flair": null,
"isNsfw": false,
"mediaType": "text",
"imageUrl": null,
"videoUrl": null,
"source": "subreddit_feed",
"status": "delivered",
"charged": true
}

The post text and the two author fields are trimmed for this page — a real row carries the body in full, as published and as HTML, and the author's name beside the stable ID behind it. A comment row carries the same columns plus the post it belongs to, its parent and its depth. Every column is listed in the table below; a row that could not be delivered carries the same columns with null in them plus a status saying why, and no result fee.

What you get

One row per post and — with Include comments on — one row per comment, on one column set whichever door the row came through. type says which it is, so a post and its thread land in the same table.

columnwhat it is
typepost or comment
id · fullname · url · permalinkthe Reddit ID, the fullname Reddit keys it by, the URL the post points at, and the reddit.com permalink
subreddit · subredditIdthe subreddit it came from, by name and by stable ID
title · text · textHtmlthe post title, the post text as published, and the same text as HTML. On a comment row, text is the comment body.
authorName · authorIdthe author's name and the stable ID behind it. A name can be changed by its owner; the ID cannot.
createdAtwhen it was published, ISO-8601 UTC
score · upvotes · upvoteRatio · commentCountthe four engagement numbers, as Reddit serves them — real values, not zeros: a measured page carried a score on 25 of 25 rows, with the upvote ratio and the comment count beside it.
flair · isNsfw · isSpoilerthe flair text, and the over-18 and spoiler flags
isVideo · postHint · domainReddit's own media hints. A row from Reddit's own search is thinner than a feed row: search does not serve flair, postHint or domain, and on those rows they are explicit nulls rather than guesses.
mediaTypetext, image, video, gallery or link
imageUrl · videoUrl · videoAudioUrl · linkUrlthe direct image link, the playable video link and its separate audio track, and the outbound link on a link post
awardshow many awards the post carries
postId · parentId · depth · isReply · collapsedon a comment row: the post it belongs to, its parent, how deep in the thread it sits, whether it replies to another comment, and whether Reddit had it collapsed
sourcethe door this row came through: subreddit_feed, search, comment or link
charged · chargedEventswhether this row was billed, and by which event. No row bills two.
status · statusReasonwhat happened, in a sentence, on every row including the ones that cost nothing

A gallery post ships as mediaType: gallery with the gallery page link and no member images. Reddit's feed carries no gallery metadata at all — no image list, no image count, nothing — verified absent across three 82 KB pages of it. The gallery link is what exists, so the gallery link is what the row says, rather than an empty column that promises pictures.

The video column no one else ships

A Reddit-hosted video post comes out playable. Reddit answers a video post with a bare v.redd.it link that plays nothing on its own, and the shelf's bigger listings hand you that link as-is. This row resolves it.

  • videoUrl is the highest rendition Reddit publishes for that video, CMAF_720.mp4, read from Reddit's own DASH manifest for the post. The manifest is a public file and reading it costs you nothing extra — there is no second event and no surcharge on a video row.
  • videoAudioUrl is a separate track, because that is how Reddit serves it: the video file carries no sound of its own. For the pictures take videoUrl, for the spoken words take videoAudioUrl, for both mux the two.
  • A video whose manifest will not answer leaves videoUrl and videoAudioUrl null with videoUrlReason saying why — and the post row is delivered and charged exactly as it would have been. A link we could not resolve never costs you the row it sits on.

What it costs

Two charged events for the rows that land, and one flat check for a page read that turns up nothing new. Nothing is charged for starting a run, and nothing is charged for a row that did not land.

eventwhat one unit isApify free planpaid plans, from
Itemone post row or one comment row, from a subreddit feed, from Reddit's own search, or from a post's comments$0.003$0.0015
Post lookupone post you named by link, delivered with the same columns$0.012$0.005
Checkone page read of a subreddit or search that turned up nothing new for you$0.005$0.005

An Item is a post or a comment — the same row and the same price either way, so the bill reads straight off the row count and nothing else.

50 posts from one subreddit is 50 items: $0.15 on the Apify free plan, $0.075 from the cheapest paid tier.

One post link with comments on is one Post lookup plus that post's first page of comments — about 25 items — so $0.087 and $0.0425. The comments ride on the same read: turning them on costs nothing beyond the rows they produce.

The check: one flat $0.005, the same on every plan. Charged once per page a run reads for a subreddit or search that turns up nothing new for you: every post and comment on it is already in your account or outside your filters (your date window, your over-18 setting) — the shape of a frequent scheduled run on a quiet subreddit. A page is one listing page of up to 25 posts, or one page of a post's comments. A subreddit or search that delivers a new post or comment pays the item fee instead, never this. A subreddit that is missing, private or banned, a search that matched nothing, a read that did not go through, a walk the run stopped before finishing, the quiet window on the Apify free plan and the built-in sample run are never charged it. One row for that subreddit or search says how many pages paid it, and the run's receipt and status line count the checks.

Comments multiply rows, and that is the one number to set before you start. 50 posts with Max comments per post at 50 is up to 2,550 rows, not 50. maxItems (default 1,000) is the ceiling on the whole run, and maxTotalChargeUsd on the run is the ceiling on the bill.

Never charged

Every one of these is still delivered as a row, labelled, with a sentence saying which it was — never a silent gap in the dataset, and never a charge. The one fee a quiet subreddit or search can carry is the check (see What it costs), on its own row that says so.

the row sayswhat happened
subreddit_unavailableReddit returned no posts for that subreddit — it may not exist, be private, be banned or simply be empty
post_not_founda post link Reddit answers with an empty shell: the post is gone, or was never there
no_resultsa search that matched nothing. Typed, never retried, and never widened
feed_unavailablethe read failed on our side. A re-run is the fix, and the row says so
unsupported_linka link this actor cannot serve: a /user/ or /wiki/ link, or a host that is not Reddit's
skipped_date_windowyour own date window dropped a post you named by link
skipped_nsfwyour own over-18 setting dropped it
skipped_seen · skipped_duplicateyour account already had that row, or the same row arrived twice inside one run. A run whose API token cannot open key-value stores can produce neither — it says so on its first row
skipped_max_items · skipped_budget · skipped_deadlineyour own row ceiling, your own maxTotalChargeUsd, or the run clock ended the collecting first
skipped_targetsthis run's own ceiling of 200 targets trimmed the rest of your list. That ceiling is ours, not yours
skipped.page_capa walk stopped at this run's own reading depth while Reddit was still serving — a subreddit, a search, or one post's comment thread. That depth is ours, not yours, and the rows behind it were never read or charged
skipped.all_repeata subreddit walk stopped because nothing new was there to read: on a run billed at the Apify free plan column the subreddit was already checked for your account within the hour, or a sort: new walk reached the newest post an earlier run had read to the end of the listing. Nothing behind that point was read or charged
vendor_budget · vendor_out_of_credita data limit of our own — this run's data budget (a re-run collects the rest straight away) or our data source paused until next month — or our collection credit running out mid-run. The row says which. All ours; none is ever yours
input_error — and input_error.subreddits, input_error.searchQueries, input_error.postUrls, input_error.startUrlssomething in that field could not be read. The row names the field, never what you typed
undeclared_fieldyou sent a field name this actor does not have, so nothing was read from it. The row names the name you sent and the field this actor uses instead, never what you typed

A walk that runs short also says WHY, on its own uncharged note row. A subreddit is read to a depth of 40 pages and one search query to 5 — so a walk that stopped there says it stopped at this run's own depth, which is ours and not a statement about what Reddit holds, and tells you what narrows the ask (a date window, a different sort, a more specific query). Only a listing that genuinely ran out says the rest does not exist to collect. Those rows are counted on the run's record as skipped.page_cap, so the depth we chose is a number you can see rather than a shortfall that quietly shrinks your ask. One post's comment thread is read to a depth of 20 pages on exactly the same rule: the post row says the thread went deeper than one run reads, and the comments behind our depth are counted the same way. Your own "Max comments per post" ending a thread is the opposite case — that is your setting, nothing was refused, and nothing is counted. And if a read fails part-way through a subreddit you were already being served, that row opens with what was already delivered — those rows are yours and each says what it was charged — and the re-run is for the rest.

And here is the one the shelf does not say out loud: a subreddit that does not exist, one that is private and one that is banned all come back as the same empty answer. Reddit tells us nothing that separates them — one identical body for all three — so the row says all three rather than picking one and sounding certain, and we do not buy a second read to guess. You are charged for none of it. The complaint that fills the Issues tabs of the biggest Reddit scrapers on this store is a run that reports success and returns nothing; this section is the answer to it.

Three things worth knowing

  • A Reddit user's own post list is not a door. Reddit does not serve it to any reader we can be. That is a fact about Reddit, not a feature waiting on a roadmap — paste that user's post links instead, and each one comes back as a full row.
  • Comments come in pages of about 25, with replies nested under their parents. Max comments per post (maxCommentsPerPost) is your cap: the run walks pages until it reaches the cap, the thread ends, or this actor's own ceiling of 20 comment pages for one post — so one thread can never spend a whole run. A post whose thread still had more keeps a comments_truncated note on its own row saying how many were delivered and which of those three stopped it. That is a note on a delivered, charged row — never a miss, and never an extra charge.
  • Search is Reddit's own search, and it returns 4 to 7 posts per page. Narrow a query with a subreddit or a date window rather than paging deep. And this actor never widens a query that came back empty — an empty search ships one no_results row and stops there. Widening is why "the results are about the wrong topic" is the second thing buyers write on a Reddit scraper's Issues tab.

How often the data changes

feedhow fast it moves
hot · risingturns over within the hour — the same run an hour later returns a different page
newa stream. It is always moving and it never repeats
topstable once its window has closed: last week's top for a finished week reads the same next month
a post's score and commentCountkeep moving for about 48 hours after it is published, then settle

The schedule that stays cheap. Run sort: new with Only posts published after (postedAfter) set to your window — a day, an hour — and the walk stops as soon as the feed goes older than that, instead of paging into posts you already hold. Your account's memory does the rest: every row this actor has already delivered to your account is skipped on the next run, no row and no charge, so a daily schedule pays for what is new, plus one $0.005 check per page read of a subreddit or search with nothing new. And a subreddit walk that meets two pages running of posts your account already has, once those cover what you asked for, stops there instead of paging on through the rest of the listing. On a run billed at the Apify free plan column this actor reads one subreddit at most once an hour for your account: a run inside that hour reads nothing for that subreddit and its uncharged note says when it was last checked. A run cut short by its time limit, your maximum cost per run or your result limit, or by Reddit not answering, is not that check, so the next run reads on. And on every plan, once a sort: new run has read a subreddit's listing to its end, a later run stops at the newest post that run saw, because everything behind it was read already. Switch Include rows you already have on to get them anyway, marked repeat: true and still uncharged. The memory is a key-value store in your own Apify account, so a run started with a scoped API token in restricted-access mode needs key-value store Read, Write and Create permission, or Actor runs set to Full access (Write is what lets the run remember what it delivered; without it every run pays again); without it the run says so on its status line and on its first row, and cannot skip what you already have.

For a leaderboard rather than a stream, sort: top over a closed timeframe is the one feed you can re-read without surprises — and the second read of it costs only one $0.005 check per page read, because the memory already has those rows — as long as the run's API token can open key-value stores in your account.

Every run ends with a receipt

The last row of every run is a receipt: rows delivered by door, post rows against comment rows, what was asked for, what your account already had, what your date window and your over-18 setting dropped, what stopped the run, and the charged totals for every event, the check included — so an invoice reconciles from the dataset itself. A cost cap or a time limit ends the collecting, never the delivering — rows already in hand are always written out.

Use it as an API endpoint (Standby)

You can also call this actor like an API: send subreddits, search terms or post links and get the rows back in the same response, with no run to start and no dataset to read. The address is on the actor's Endpoints tab, where you can also try it from the browser.

curl -H "Authorization: Bearer <YOUR_APIFY_TOKEN>" \
"https://steadyfetch--reddit-scraper.apify.actor/?subreddits=smallbusiness&maxItems=1"

It takes the same fields as a run — subreddits, searchQueries, postUrls, startUrls, sort, searchSort, timeframe, resultsLimit, maxItems, includeComments, maxCommentsPerPost, postedAfter, postedBefore, includeNsfw — in the query string (subreddits and links separated by commas; repeat searchQueries for more than one term) or as a JSON body with POST. One request takes at most 10 subreddits, search terms and post links in all and returns at most 300 rows (one input and 25 rows on the Apify free plan); a longer list is a run.

The answer is JSON: rows (the same rows a run writes to its dataset), summary (the same receipt row a run ends on), delivered, charged per event, and notes for anything that was not returned, in plain words. You are charged per row returned, at the same per-row prices as a run — an Item for a post or a comment, a Post lookup for a post you named by link, exactly as in the table above — and the same check per page read of a subreddit or search that turns up nothing new (see What it costs); with no account memory here, that is a page whose every post is outside your date window or over-18 setting. A request that returns no rows is charged nothing beyond that check, and if the charge for a request cannot be completed, its rows are not sent and nothing is charged.

Good to know: the endpoint keeps no memory of your account — every request returns, and charges, the posts it reads, including ones you collected before. So includeSeen, resumeFromDatasetId and webhooks, which read your own Apify account, are refused there with a note saying so. For a schedule that pays only for what is new, run the actor as usual.

  • The spoken words of a Reddit video: hand videoAudioUrl to steadyfetch/media-transcriber in its urls field — the audio track is the one with sound in it.
  • Comments under a Facebook post: steadyfetch/facebook-comments-scraper. Posts from a Facebook page or public group: steadyfetch/facebook-posts-scraper.

Something not right?

Open the Issues tab on this actor with your run ID and the input you used, and it gets looked at. If it earned its keep, a rating helps other buyers find it, and saving the actor keeps it one click away.