Reddit Scraper — Posts, Comments, Search, Subreddit Monitoring
Pricing
from $2.00 / 1,000 posts
Reddit Scraper — Posts, Comments, Search, Subreddit Monitoring
Subreddit listings, keyword search and full comment trees, no login and no proxy to configure. Posts with full text, score, flair and media; comments with depth and parent. Schedule it with onlyNew to get just what appeared since the last run. Pay per row, no start fee.
Pricing
from $2.00 / 1,000 posts
Rating
0.0
(0)
Developer
Moxlade
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
2 days ago
Last modified
Categories
Share
Subreddit listings, keyword search and full comment trees — no Reddit login, no proxy to set up, no start fee. Give it subreddits, search queries or post URLs and get posts with their full text, score, upvote ratio, flair and media, and comments with author, score, depth and parent. Turn on onlyNew and schedule it: each run returns only what appeared since the last one, and a run with nothing new costs nothing. Pay per delivered row — $2.00 per 1,000 posts, $1.00 per 1,000 comments.
What you get
- Three ways in, one row shape.
subredditswalks a listing bynew,hot,top(with a time range) orrising;searchesruns Reddit's own post search, sitewide or inside each subreddit you name;postUrlsfetches specific posts. Every row is the same 27 typed fields,kind=postorcomment,found_bysays which input produced it. - Full text on every post, not a preview. Listing posts carry the complete body as Reddit renders it (
body_textwith paragraph breaks,body_htmlwith links), the score, upvote ratio, comment count, flair, type, media URLs, language, stickied/locked flags. Search hits are filled with author and body (fetchBodies, on by default). - Comment trees with structure.
includeCommentsdelivers each post's comments right after it —depth,parent_id,post_id, author, score, permalink — in Reddit'sBest/Top/New/… order, deep branches expanded up tomaxCommentsPerPost. - Monitoring that remembers.
onlyNewkeeps the ids it delivered in a named store and, on a chronological walk, the newest post it delivered per source; the next run stops at that point. Schedule a task and each run is the delta — the same lever aspostedSince(12h,7d,2w, a date) for a one-off window. - Nothing to configure, nothing to babysit. No cookies, no account, no proxy field. Reddit is read from a maintained residential exit that rotates on any wall and waits out the rate limit; a page that fails is retried before the run is failed, and the failure reason is in the status message.
- Measured, not promised. The acceptance suite runs the deployed build before every release. On the release runs: 25 listing rows with score, ratio, counts, type, flags and language on 25 of 25; 20 search rows with author and body on 20 of 20; a thread of 40 comments with a resolved parent on 22 of 22 nested comments; the second monitoring run at 0 rows and $0.00.
Who it's for
- Community and brand monitoring — watch the subreddits and keywords that matter, on a schedule, and get only the new posts — with the text, not a link to click.
- Research and content teams — pull a subreddit's top posts of the month with their comment trees, or every post matching a query since a date, into one typed dataset.
- Product and lead-gen builders — a stable id (
id),permalink,created_utcandfound_byon every row, so deduplication, joins and incremental pulls are one line each. - Data pipelines and AI agents — one call, JSON rows with full text and structure, no browser and no login to keep alive.
Quick start
Newest posts in a subreddit
{"subreddits": ["Upwork"],"sort": "new","maxItems": 50}
Top posts of the month with their comments
{"subreddits": ["ClaudeCode"],"sort": "top","time": "month","includeComments": true,"maxCommentsPerPost": 50,"maxItems": 25}
Search a topic across Reddit since a date
{"searches": ["claude code"],"searchSort": "new","postedSince": "7d","maxItems": 100}
Search inside chosen subreddits
{"subreddits": ["ClaudeCode","ChatGPTCoding"],"searches": ["hooks","mcp server"],"maxItems": 100}
Specific posts with every comment
{"postUrls": ["https://www.reddit.com/r/Upwork/comments/1wd745i/here_are_my_tips_for_upwork_newcomers/"],"includeComments": true,"maxCommentsPerPost": 500}
Monitor: only what is new since the last run
{"subreddits": ["Upwork","freelance"],"sort": "new","onlyNew": true,"maxItems": 200}
Output
One row per post or comment (kind says which):
| field | meaning |
|---|---|
kind | post or comment. |
id | Reddit's own id: t3_… for a post, t1_… for a comment. Stable; deduplicate and join on it. |
subreddit | Subreddit name without the r/. |
title | Post title. Null on comment rows. |
author | Username without the u/. Null when the account is deleted. |
created_utc | When it was posted, ISO 8601 UTC. |
score | Net upvotes as Reddit showed them at fetch time. Null on a post reached by URL alone — Reddit's post page carries no score for a visitor; a post reached through a subreddit listing or a search has it. |
upvote_ratio | Share of upvotes, 0–1. Subreddit listings only. |
comment_count | Comments on the post as Reddit counts them (a comment row carries the count of its post). |
post_type | text, image, gallery, video, multi_media, crosspost, link or poll. Subreddit listings only. |
flair | The post's flair text, when it has one. |
url | What the post links to: the external URL, the media, or the crossposted post. For a text post this is its own permalink. |
domain | Domain of url as Reddit labels it (self.<sub> for text posts, i.redd.it, youtube.com, …). |
permalink | The post's or comment's own URL on reddit.com. |
body_text | Full text of the post or comment, paragraphs separated by blank lines. Empty for a link post. |
body_html | The same body as Reddit's rendered HTML, links kept. |
media | Media URLs the post carries (images, galleries, video). |
nsfw | Marked NSFW. Known on search hits; null where Reddit did not say. |
stickied | Pinned by the moderators. Subreddit listings only. |
locked | Comments locked. Subreddit listings only. |
language | Reddit's language tag for the post (en, de, …). Subreddit listings only. |
award_count | Awards on the post. Subreddit listings only. |
post_id | Comment rows: the t3_… id of the post the comment belongs to. |
parent_id | Comment rows: the id of the parent comment (t1_…), or null for a top-level comment. |
depth | Comment rows: 0 for a top-level comment, 1 for a reply to it, and so on. |
found_by | How the row was reached: r/<sub>/<sort> for a subreddit listing, search:<query> (with @r/<sub> when scoped), url for a post given by URL, and comments:<post id> for a comment. |
fetched_at | When this row was read from Reddit, ISO 8601 UTC. |
Example record:
{"kind": "post","id": "t3_1wd745i","subreddit": "Upwork","title": "Here are my tips for Upwork newcomers as a top Freelancer","author": "Pierre_Zarokian","created_utc": "2026-09-11T05:27:33.222000+00:00","score": 47,"upvote_ratio": 0.7582417582417582,"comment_count": 66,"post_type": "text","flair": null,"url": "https://www.reddit.com/r/Upwork/comments/1wd745i/here_are_my_tips_for_upwork_newcomers_as_a_top/","domain": "self.Upwork","permalink": "https://www.reddit.com/r/Upwork/comments/1wd745i/here_are_my_tips_for_upwork_newcomers_as_a_top/","body_text": "My stats: 5 years, $500K+ earned, ~900 jobs completed.\n\nMy #1 tip: Find an uncrowded niche. My core skill set is digital marketing and SEO, but the mainstream lanes such as SEO, Google Ads, social media marketing are too saturated. Instead, I built my practice around Online Reputation Management, PR, and Wikipedia page creation. Wikipedia work was a strong earner for years until Upwork restricted it about a year ago. Since then, I've shifted mainly to ORM and PR, and I've started picking up AEO (Answer Engine Optimization) jobs too — it's far less competitive than SEO, and I've already landed 2 AEO contracts in the past few months.\n\nAdditional tips:\n\nMove fast. Try to be among the first 10–15 applicants on any job post, ideally applying within 15 minutes of it going live. Earlier bids win more often.\n\nSkip overcrowded listings. Don't bother applying once a job already has 20–50 proposals — unless you're confident you're a top-tier fit and the budget justifies it.\n\nBid for visibility. Aim to be the #1 bidder when you can, but set yourself a spending cap (say, 20–30 connects) so you don't overspend chasing hyper-competitive listings.\n\nDon't chase underpriced jobs hoping to negotiate up. Check the client's hiring history and average hourly rate paid. If they've hired 20+ freelancers averaging $10/hour, walk away unless that rate works for you. Personally, I won't bid below $75/hour.\n\nKeyword-optimize your profile. Your headline and overview should reflect the terms clients actually search for.\n\nTarget jobs with your keywords in the title. If a client wants to hire you under a vague or irrelevant job title, ask them to repost with a more specific, keyword-aligned title before accepting.\n\nAlways secure reviews. If a client doesn't leave one after project completion, follow up more than once to ask.\n\nGet direct contact info. Once hired, ask for the client's phone number and email, which will be useful if they go unresponsive, and handy later when requesting a review.\n\nStrengthen your proposals with proof. Attach case studies, testimonials, and a client list (especially if it includes recognizable brands).\n\nFeature your reviews. Include 4 strong job reviews at the bottom of every proposal.\n\nPersonalize every application. Even reused templates should open with a line specific to that client's stated needs, so it doesn't read as copy-paste.\n\nProject confidence. Don't undersell your experience. Use phrases like \"I'm the best candidate for this, look no further.\"\n\nUnderprice early to build your review base. In your first few months, take lower-paying jobs to get hired more often and rack up reviews. Once you hit 10–20 reviews, gradually raise your rates.\n\nApply to small unrelated gigs to increase your reviews. Take on $5–$50 jobs in unrelated categories (survey/review-type gigs, for instance) purely to build your review history, even though some of these may be against Upwork's policies.\n\nGood luck and reach out if you have any questions.","body_html": "<p>\n <strong>My stats:</strong> 5 years, $500K+ earned, ~900 jobs completed.\n </p><p>\n <strong>My #1 tip: Find an uncrowded niche.</strong> My core skill set is digital marketing and SEO, but the mainstream lanes such as SEO, Google Ads, social media marketing are too saturated. Instead, I built my practice around Online Reputation Management, PR, and Wikipedia page creation. Wikipedia work was a strong earner for years until Upwork restricted it about a year ago. Since then, I've shifted mainly to ORM and PR, and I've started picking up AEO (Answer Engine Optimization) jobs too — it's far less competitive than SEO, and I've already landed 2 AEO contracts in the past few months.\n </p><p>\n <strong>Additional tips:</strong>\n </p><ul>\n <li>\n <p>\n <strong>Move fast.</strong> Try to be among the first 10–15 applicants on any job post, ideally applying within 15 minutes of it going live. Earlier bids win more often.\n </p>\n </li><li>\n <p>\n <strong>Skip overcrowded listings.</strong> Don't bother applying once a job already has 20–50 proposals — unless you're confident you're a top-tier fit and the budget justifies it.\n </p>\n </li><li>\n <p>\n <strong>Bid for visibility.</strong> Aim to be the #1 bidder when you can, but set yourself a spending cap (say, 20–30 connects) so you don't overspend chasing hyper-competitive listings.\n </p>\n </li><li>\n <p>\n <strong>Don't chase underpriced jobs hoping to negotiate up.</strong> Check the client's hiring history and average hourly rate paid. If they've hired 20+ freelancers averaging $10/hour, walk away unless that rate works for you. Personally, I won't bid below $75/hour.\n </p>\n </li><li>\n <p>\n <strong>Keyword-optimize your profile.</strong> Your headline and overview should reflect the terms clients actually search for.\n </p>\n </li><li>\n <p>\n <strong>Target jobs with your keywords in the title.</strong> If a client wants to hire you under a vague or irrelevant job title, ask them to repost with a more specific, keyword-aligned title before accepting.\n </p>\n </li><li>\n <p>\n <strong>Always secure reviews.</strong> If a client doesn't leave one after project completion, follow up more than once to ask.\n </p>\n </li><li>\n <p>\n <strong>Get direct contact info.</strong> Once hired, ask for the client's phone number and email, which will be useful if they go unresponsive, and handy later when requesting a review.\n </p>\n </li><li>\n <p>\n <strong>Strengthen your proposals with proof.</strong> Attach case studies, testimonials, and a client list (especially if it includes recognizable brands).\n </p>\n </li><li>\n <p>\n <strong>Feature your reviews.</strong> Include 4 strong job reviews at the bottom of every proposal.\n </p>\n </li><li>\n <p>\n <strong>Personalize every application.</strong> Even reused templates should open with a line specific to that client's stated needs, so it doesn't read as copy-paste.\n </p>\n </li><li>\n <p>\n <strong>Project confidence.</strong> Don't undersell your experience. Use phrases like \"I'm the best candidate for this, look no further.\"\n </p>\n </li><li>\n <p>\n <strong>Underprice early to build your review base.</strong> In your first few months, take lower-paying jobs to get hired more often and rack up reviews. Once you hit 10–20 reviews, gradually raise your rates.\n </p>\n </li><li>\n <p>\n <strong>Apply to small unrelated gigs to increase your reviews.</strong> Take on $5–$50 jobs in unrelated categories (survey/review-type gigs, for instance) purely to build your review history, even though some of these may be against Upwork's policies.\n </p>\n </li>\n </ul><p>\n Good luck and reach out if you have any questions.\n </p>","media": [],"nsfw": false,"stickied": false,"locked": false,"language": "en","award_count": 0,"post_id": null,"parent_id": null,"depth": null,"found_by": "r/Upwork/new","fetched_at": "2026-09-12T21:29:45Z"}
Pricing
Pay per delivered row, nothing else. post — one post row, from a listing, a search or a URL — $2.00 per 1,000. comment — one comment row (includeComments) — $1.00 per 1,000. No start fee, no minimum, and a run that returns nothing costs nothing: on the acceptance runs the charged event count equals the row count on every run, and the zero-row run charged $0.00. A row is charged only after it is in your dataset, so maxItems and maxCommentsPerPost together are your spending cap.
Usage patterns
- List a subreddit — Set
subredditsand asort.newis chronological — pair it withpostedSincefor a window oronlyNewfor a schedule.topwithtimegives the period's best.maxPostsPerSourcesays how far down each listing to look (Reddit itself stops at about 1,000). Ready-made: Newest posts in a subreddit and Top posts of the month, with their comments. - Search for posts — Set
searches; each query runs across Reddit, or inside each ofsubredditswhen both are given.searchSortis Reddit's own ordering (new,relevance,hot,top,comments). Hits come with author and full text unless you turnfetchBodiesoff to save the extra request per post. Ready-made: Search Reddit for a topic, last 7 days. - Fetch posts by URL, with their comments — Paste post URLs or ids into
postUrls, turn onincludeComments, setmaxCommentsPerPostandcommentSort. Comments follow their post in the dataset, each withdepthandparent_id. A post reached by URL alone carries no score (Reddit's post page shows a visitor none); posts reached through a listing or a search do. - Monitor on a schedule — Turn on
onlyNew, save the run as a task, add a schedule. The first run seeds the memory; every later run delivers only what appeared since, or nothing at all — and nothing is charged for nothing. Name the memory withstateStoreNameto share it between tasks or to reset it. Ready-made, schedule it: Monitor subreddits: only new posts each run.
Input configuration
| field | type | default | what it does |
|---|---|---|---|
subreddits | array | Subreddit names or URLs (Upwork, r/Upwork, https://www.reddit.com/r/Upwork/). Each is listed by sort and time. With searches set as well, every search runs inside each of these subreddits instead. | |
sort | new / hot / top / rising | "new" | How each subreddit is listed. new is chronological, which is what postedSince and onlyNew walk most cheaply. |
time | hour / day / week / month / year / all | "week" | Applies to sort: top only. |
searches | array | Keyword searches for posts, across all of Reddit — or inside each of subreddits when both are given. One row per matching post. | |
searchSort | new / relevance / hot / top / comments | "new" | Order of search results, as Reddit's own search offers it. |
postUrls | array | Specific posts to fetch: URLs (https://www.reddit.com/r/Upwork/comments/1w8w2hb/…) or ids (1w8w2hb, t3_1w8w2hb). Each comes back with its full body and, with includeComments, its comment tree. | |
includeComments | boolean | false | Fetch the comment tree of every delivered post — one comment row per comment, with author, score, depth and parent, right after its post. Billed as comment per row. |
maxCommentsPerPost | integer | 100 | Cap on comment rows per post. Deep threads are expanded breadth-first until the cap. |
commentSort | confidence / top / new / controversial / old / qa | "confidence" | Reddit's comment ordering for the tree. |
fetchBodies | boolean | true | A search hit alone carries title, score, comment count and date. Leave this on to read each hit's author and full text as well (one extra request per post). Subreddit listings and post URLs always carry the body. |
postedSince | string | Keep only posts created after this point: a date (2026-09-01), a timestamp, or a window before now — 12h, 7d, 2w, 1m. With sort: new the listing walk stops at the cutoff, so nothing older is fetched. | |
onlyNew | boolean | false | Remember every post delivered and skip it next time. Schedule the task and each run returns only what appeared since the previous one — a run with nothing new delivers no rows and costs nothing. The memory is a named key-value store (stateStoreName, or one derived from the targets when left empty). |
stateStoreName | string | Name of the key-value store that keeps the delivered ids for onlyNew. Leave empty to derive one from the subreddits, searches and post URLs; set it to share one memory between tasks or to reset it (a new name starts fresh). | |
maxItems | integer | 100 | Stop after this many post rows across the whole run. Comment rows are bounded separately by maxCommentsPerPost. With no start fee, this is also your spending cap: posts × $0.002 (+ comments × $0.001). |
maxPostsPerSource | integer | 100 | How far down each listing or search to look. Reddit itself stops a listing at about 1,000 posts. |
FAQ
Does it need a Reddit account or a proxy?
No. Reddit is read logged out, through an exit we maintain, and nothing is stored on your side. There is no cookie or proxy field because there is nothing for you to supply.
Why does a post fetched by URL have no score?
Reddit's post page renders nothing but a script shell to a visitor; the post's body and its comment tree come from two other endpoints that do not carry the post's score. A post reached through a subreddit listing or a search has its score, upvote ratio and comment count, because those pages do.
How many comments does a post return?
Up to maxCommentsPerPost (default 100, up to 2,000). The first page of a thread holds about 25 top-level comments with their visible replies; deeper branches are expanded breadth-first until the cap. A thread's comment_count is Reddit's total; the delivered count can be lower when comments are deleted or collapsed.
What does a run cost?
One event per row that lands in your dataset — $2 per 1,000 posts, $1 per 1,000 comments — nothing for the run itself and nothing for a zero-row run. Measured on our release runs: 25 listing rows in a 6 s run, 20 search rows with bodies in 26 s, one post with 40 comments in 17 s.
Who makes this, and what else is there?
Moxlade — corpora your agent can ask. Its other actor is the Upwork freelancer census (search by rate, JSS, badge, country; exact earnings; every contract), and its MCP endpoint for Upwork buyer intelligence is buyer.moxlade.com. Working code for the same client calls, in Python, JavaScript and curl: github.com/getmoxlade/upwork-freelancers-examples — this actor takes the same calls with its own input.
Is the data current?
Every row is read from Reddit at run time — fetched_at says when — so scores and comment counts are what Reddit showed at that moment.
Integration
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('moxlade/reddit-scraper').call({"subreddits": ["Upwork"], "sort": "new", "maxItems": 50});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Python
from apify_client import ApifyClientclient = ApifyClient('YOUR_TOKEN')run = client.actor('moxlade/reddit-scraper').call(run_input={'subreddits': ['Upwork'], 'sort': 'new', 'maxItems': 50})items = client.dataset(run['defaultDatasetId']).list_items().items
CLI
$apify call moxlade/reddit-scraper --input '{"subreddits": ["Upwork"], "sort": "new", "maxItems": 50}'
REST
curl -X POST "https://api.apify.com/v2/acts/moxlade~reddit-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H 'Content-Type: application/json' -d '{"subreddits": ["Upwork"], "sort": "new", "maxItems": 50}'
Support
This page is generated from the Actor's schemas and a live sample — it cannot describe a field the Actor does not have.