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

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

Pricing

from $1.50 / 1,000 items

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

Reddit Scraper — Subreddit 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, no result fee.

Pricing

from $1.50 / 1,000 items

Rating

0.0

(0)

Developer

Steadyfetch Team

Steadyfetch Team

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

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 you have 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.

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 only when a row lands in your dataset: 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. 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

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.

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 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
vendor_budget · vendor_out_of_creditour own monthly collection allowance, or our collection credit running out mid-run. Both ours; neither 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 and nothing else. 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 nothing, 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 both events — 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.

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