# Reddit Post Comments Scraper - Full Threads to CSV & Markdown (`seemuapps/reddit-post-comments-scraper`) Actor

Scrape every comment and nested reply from any Reddit post - one row per comment with depth, parent and score - plus a Markdown copy of the thread for LLMs.

- **URL**: https://apify.com/seemuapps/reddit-post-comments-scraper.md
- **Developed by:** [Andrew](https://apify.com/seemuapps) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 comments

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Reddit Post Comments Scraper - Full Threads to CSV & Markdown

Paste any Reddit post URL and get back every comment and nested reply as its own row - author, score, timestamp, depth and parent - in the exact order the thread reads on Reddit. Optionally save the whole discussion as a clean Markdown document, ready to feed into ChatGPT, Claude, a RAG index or a summariser. No Reddit login, no API key, no rate limits to manage.

Long threads are handled properly: the scraper keeps turning comment pages until it has the number of comments you asked for, and can follow Reddit's collapsed "load more replies" branches so deep conversations are not cut off.

### What you get

One dataset row per comment (`type: "comment"`):

- **commentId**, **parentId**, **depth** - the thread structure, flattened. `depth` is 0 for top-level comments; `parentId` is the post ID for top-level comments and the parent comment ID for replies
- **author**, **body**, **score**, **createdAt**, **permalink**
- **isOp** - true when the comment was written by the post author
- **collapsed** - whether Reddit collapsed it by default (heavily downvoted, etc.)
- **replyCount** - number of direct replies present in the fetched tree
- **postId**, **postUrl**, **postTitle**, **subreddit** repeated on every row so a multi-post export still filters and pivots cleanly

One optional row per post (`type: "post"`) with **postTitle**, **selftext**, **author**, **score**, **upvoteRatio**, **numComments**, **createdAt**, **flair**, **linkUrl** and **commentsFetched**.

Plus, when **Save thread as Markdown** is on, one `THREAD_<postId>.md` file per post in the run's Key-value store: the title, post body and the complete comment tree rendered as indented blockquotes with author, score and timestamp headers.

Rows are written in depth-first thread order, so reading the dataset top to bottom is the same as reading the thread.

### Use cases

- **Reddit thread to Markdown for LLM / RAG** - drop an entire discussion into a prompt, a vector store or a summarisation pipeline without writing a parser
- **Sentiment and opinion mining** - collect what thousands of people said about a product, launch or event, with scores to weight each voice
- **Market and product research** - harvest recommendations, complaints and comparisons from "what do you use for X" threads
- **Community and brand monitoring** - archive the full reaction to an announcement or AMA before comments are deleted
- **Dataset building** - build labelled conversation trees (parent/child pairs, depth, score) for NLP and social-science research
- **Content ideation** - find the questions, objections and follow-ups a topic attracts so your next article answers them

### How to use

1. Paste one or more **Reddit post URLs**, one per line. Full thread links, comment permalinks, `redd.it/<id>` short links and bare post IDs all work.
2. Pick the **Comment order** - Best (Reddit's default), Top, New or Controversial. This decides which comments come first when a thread is bigger than your limit.
3. Set **Max comments per post** (default 500; `0` = everything the request budget allows).
4. **Max requests per post** (default 20) is the cost ceiling per thread. Each request returns roughly 25-100 comments.
5. Turn on **Expand collapsed reply branches** when you need every reply in long, deep conversations. Each branch costs one extra request.
6. Optionally set a **Minimum comment score** to drop low-value comments (their replies are dropped too, so the tree stays consistent).
7. Leave **Include post row** on to get the original post as the first row of each thread.
8. Turn on **Save thread as Markdown** to also get `THREAD_<postId>.md` files.
9. Run the actor. Comments appear in the **Dataset** tab; Markdown files in the **Key-value store** tab.

### Output format

Post row followed by its comments:

```json
{
  "type": "post",
  "postId": "1wgo85o",
  "postUrl": "https://www.reddit.com/r/typescript/comments/1wgo85o/need_recommendation_on_guide_on_typescript_that/",
  "postTitle": "need recommendation on guide on typescript that deals with server and linting",
  "subreddit": "typescript",
  "author": "techlover1010",
  "selftext": "anyone can recommend me some great resource on server and linting with type script? ...",
  "score": 0,
  "upvoteRatio": 0.27,
  "numComments": 8,
  "createdAt": "2026-09-15T02:55:28.000Z",
  "flair": null,
  "linkUrl": null,
  "commentsFetched": 7
}
```

```json
{
  "type": "comment",
  "postId": "1wg736i",
  "postUrl": "https://www.reddit.com/r/AskReddit/comments/1wg736i/what_hobby_has_become_too_expensive_for_the/",
  "postTitle": "What hobby has become too expensive for the average person?",
  "subreddit": "AskReddit",
  "commentId": "p9rvsy5",
  "parentId": "p9rvgfw",
  "depth": 1,
  "author": "DifficultYellow9759",
  "body": "Took my son and his friend bowling and it cost me $125 for 3 games, shoes, and some apps.\n\n I could have taken them to a water park for that money and it would have been an all day activity versus 2 hours",
  "score": 430,
  "createdAt": "2026-09-14T15:51:09.000Z",
  "permalink": "https://www.reddit.com/r/AskReddit/comments/1wg736i/comment/p9rvsy5/",
  "isOp": false,
  "collapsed": false,
  "replyCount": 0
}
```

The Markdown file for a thread looks like this:

```markdown
## need advice on this issue

**r/typescript** · posted by u/techlover1010 · 0 points (43% upvoted) · 13 comments · 2026-09-12T03:25:19Z

Source: https://www.reddit.com/r/typescript/comments/1we1ckz/need_advice_on_this_issue/

I have a problem. im using node and typescript ...

---

### Comments (9 of 13)

**u/Beginning-Seat5221** · 6 points · 2026-09-12T03:34:48Z

Don't pass file.ts, just npm tsc

> **u/techlover1010** · 1 point · 2026-09-12T05:07:47Z · **OP**
>
> do you think you can check my second question ...

> > **u/Beginning-Seat5221** · 1 point · 2026-09-12T12:13:39Z
> >
> > I did at 2. Which version of TS are you using?
```

### Pricing

Three small events: one `comments-page` event per page of comments fetched (roughly 100 comments per page on large threads), one `comment-result` event per comment row and one `post-result` event per post row. A 300-comment thread is about 5 page events plus 300 comment events plus one post event; the Markdown file is free.

### Tips

- **Top** order with a modest **Max comments per post** gives you the highest-signal part of a huge thread cheaply; **Best** (the default) mirrors what a visitor sees on Reddit.
- Reddit reports `numComments` including deleted, removed and collapsed comments, so the number of rows is usually a little lower than the post's comment count even when you fetch everything.
- For threads with thousands of comments, raise **Max requests per post** together with **Max comments per post** - each request returns up to about 100 comments after the first page.
- Turn on **Expand collapsed reply branches** only when you need the long tails of deep conversations; branch requests often return only a handful of replies each.

### FAQ

**Do I need Reddit API credentials?**
No. Everything runs without a login or API key.

**Can I get the whole thread, not just the first page?**
Yes. Set **Max comments per post** to `0` and raise **Max requests per post**; the scraper keeps paginating until Reddit runs out of comments or the budget is spent.

**Why is the comment count lower than Reddit's number?**
Reddit's counter includes deleted and removed comments and replies hidden behind "load more" links. Enable branch expansion to pull in the hidden ones; deleted comments cannot be recovered.

**What is the difference between depth and parentId?**
`depth` tells you how far the comment is nested (0 = top level). `parentId` tells you exactly which comment (or post) it replies to, so you can rebuild the tree or extract parent-child pairs.

# Actor input Schema

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

Posts to scrape, one per line. Accepts full thread URLs (reddit.com/r/.../comments/<id>/...), comment permalinks, short redd.it/<id> links, or bare post IDs like 1wg736i.

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

Order in which Reddit serves the top-level comments. Determines which comments you get first when a thread is larger than Max comments per post.

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

Stop after this many comments (including nested replies) for each post. 0 = fetch everything available, bounded only by Max requests per post and the run timeout.

## `maxCommentPagesPerPost` (type: `integer`):

Hard cap on comment pages fetched for one post (each page returns roughly 25-100 comments). Also bounds reply-branch expansion when it is enabled. Acts as a cost ceiling per thread.

## `expandReplyBranches` (type: `boolean`):

Follow Reddit's 'load more replies' links inside deep conversations after all top-level pages are fetched. Each branch costs one extra request from the per-post budget. Leave off for the cheapest run; turn on when you need every reply.

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

Skip comments whose score is below this value. The skipped comment's replies are skipped too so parentId always points at a comment in the dataset. Leave empty to keep every comment, including downvoted ones.

## `includePostRow` (type: `boolean`):

Push one extra row per thread with type 'post' carrying the title, body, score, upvote ratio and comment count of the original post, before its comments.

## `outputMarkdown` (type: `boolean`):

Also write one Markdown file per post to the Key-value store (THREAD\_<postId>.md) with the title, post body and the nested comment tree rendered as indented blockquotes - ready to drop into an LLM prompt or a RAG index.

## Actor input object example

```json
{
  "postUrls": [
    "https://www.reddit.com/r/AskReddit/comments/1wg736i/what_hobby_has_become_too_expensive_for_the/"
  ],
  "sort": "best",
  "maxCommentsPerPost": 200,
  "maxCommentPagesPerPost": 20,
  "expandReplyBranches": false,
  "includePostRow": true,
  "outputMarkdown": true
}
```

# Actor output Schema

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

Rows with type 'comment': postId, postUrl, postTitle, subreddit, commentId, parentId, depth, author, body, score, createdAt, permalink, isOp, collapsed, replyCount - in depth-first thread order. Rows with type 'post': postId, postUrl, postTitle, subreddit, author, selftext, score, upvoteRatio, numComments, createdAt, flair, linkUrl, commentsFetched.

## `threadMarkdown` (type: `string`):

When 'Save thread as Markdown' is on, each post is rendered to THREAD\_<postId>.md in the default key-value store: title, post body and the nested comment tree as indented blockquotes.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "postUrls": [
        "https://www.reddit.com/r/AskReddit/comments/1wg736i/what_hobby_has_become_too_expensive_for_the/"
    ],
    "maxCommentsPerPost": 200,
    "outputMarkdown": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("seemuapps/reddit-post-comments-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "postUrls": ["https://www.reddit.com/r/AskReddit/comments/1wg736i/what_hobby_has_become_too_expensive_for_the/"],
    "maxCommentsPerPost": 200,
    "outputMarkdown": True,
}

# Run the Actor and wait for it to finish
run = client.actor("seemuapps/reddit-post-comments-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "postUrls": [
    "https://www.reddit.com/r/AskReddit/comments/1wg736i/what_hobby_has_become_too_expensive_for_the/"
  ],
  "maxCommentsPerPost": 200,
  "outputMarkdown": true
}' |
apify call seemuapps/reddit-post-comments-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,seemuapps/reddit-post-comments-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/hQpX9quU2BauAQUMY/builds/ca9qxj9iafaC0xqDx/openapi.json
