# Reddit Comments Scraper - Post and All Comments (`kaix/reddit-comments-scraper`) Actor

🔥 ~$0.02/1K comments 🔥 Get a Reddit post and every comment on it, from the post URL. No account needed. Large threads save as they load. Clean, flat JSON with the post, parent and depth of each comment.

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

## Pricing

from $0.02 / 1,000 reviews

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Comments Scraper - Post and All Comments

Get a Reddit post and every comment on it. Start with post URLs. Each post comes
first, then all of its comments as flat records. Each comment has the ID of its
post, the ID of its parent, and its depth, so you can rebuild the whole thread.
You do not need a Reddit account.

Read a few comments or the full thread of a post. Large threads work. Without a
limit, comments go to the dataset while they load, so a thread with 15,000
comments needs no special setup.

### What can you do with it?

- **Sentiment and topic analysis.** Feed comment text, scores, and dates into your
  models.
- **Full discussion archives.** Save every reply of a thread, also a thread with
  tens of thousands of comments.
- **Brand and product research.** Read what people say about a product in the
  comments of a launch post or a review thread.
- **Community research.** See which comments get the most votes, and how a
  discussion develops by depth.
- **Training data.** Build conversation datasets. Each reply points to its parent,
  so the tree is complete.
- **Moderation review.** Read a whole thread in one place, with the distinguished
  and stickied flags.
- **Monitoring.** Run the Actor on a schedule for a set of posts, and keep the
  comments with a new `id`.

### What data does it extract?

Posts and comments are in the same dataset. Use the `type` field to tell them
apart.

| Data | When you get it |
|---|---|
| Post ID, title, text, link, domain, and permalink | Every post |
| Subreddit name, ID, type, and subscriber count | Every post |
| Post author, author flair, and Premium flag | Every post |
| Score, upvote ratio, comment count, crosspost count, and award count | Every post |
| Created time and edit state | Every post |
| Post flags: over 18, spoiler, stickied, locked, archived, quarantine, and more | Every post |
| Post flair with its colors | When the post has flair |
| Thumbnail, preview images, gallery images, and video | When the post has them |
| HTML text of the post | When `depth` is `detailed` |
| Comment ID, text, score, created time, edit state, and permalink | Every comment |
| Post ID, parent ID, and depth | Every comment |
| Comment author, author flair, Premium flag, and the post author flag | Every comment |
| Controversiality, award count, and hidden score flag | Every comment |
| Stickied, distinguished, and collapsed flags | Every comment |
| HTML text of the comment | When `depth` is `detailed` |

Reddit does not have every field for every item. A field without data is `null`.

### Quick start

1. Enter one or more Reddit post URLs in **Post URLs or IDs**.
2. Leave **Max comments per post** at `0` to get every comment.
3. Click **Start**. Download the results as JSON, CSV, Excel, or HTML.

The same input as JSON:

```json
{
  "postUrls": ["https://www.reddit.com/r/MachineLearning/comments/1qo6sai/"]
}
```

The **Output** tab has a **Posts** table and a **Comments** table. In the API,
read the dataset items and filter on `type`.

### Examples by use case

**Every comment of one post.** This also works for a post with thousands of
comments:

```json
{
  "postUrls": ["https://www.reddit.com/r/MachineLearning/comments/1qo6sai/"],
  "maxCommentsPerPost": 0
}
```

**The first 100 comments of several posts.** One run reads all the posts. The
dataset keeps the order of your list. Each post comes before its comments:

```json
{
  "postUrls": [
    "https://www.reddit.com/r/MachineLearning/comments/1rc3nez/",
    "t3_1w10tax",
    "https://redd.it/1w1wt1s"
  ],
  "maxCommentsPerPost": 100
}
```

**The best comments of a big thread.** The `top` sort and a limit give you the
highest scored top-level comments first, then their replies, up to the limit:

```json
{
  "postUrls": ["https://www.reddit.com/r/MachineLearning/comments/1qo6sai/"],
  "commentSort": "top",
  "maxCommentsPerPost": 200
}
```

**The newest comments.** Use this to monitor a post that is still active:

```json
{
  "postUrls": ["https://www.reddit.com/r/MachineLearning/comments/1qo6sai/"],
  "commentSort": "new",
  "maxCommentsPerPost": 100
}
```

**HTML text.** Set `depth` to `detailed` to get the HTML text of the post and of
each comment, with links and formatting:

```json
{
  "postUrls": ["https://www.reddit.com/r/MachineLearning/comments/1qo6sai/"],
  "depth": "detailed",
  "maxCommentsPerPost": 50
}
```

**The post only.** Set `maxCommentsPerPost` to `1` to get the post record and one
comment. There is no setting for zero comments.

### Choose the posts

Put one or more entries in `postUrls`. Each entry is one of these:

- **A post URL.** A link that has `/comments/` and the post ID, such as
  `https://www.reddit.com/r/MachineLearning/comments/1qo6sai/title/`. The
  subreddit part of the URL is not used. Only the ID counts. A link to a single
  comment also gives the whole post.
- **A short link.** A `redd.it` link, such as `https://redd.it/1qo6sai`.
- **A fullname.** The `t3_` prefix and the ID, such as `t3_1qo6sai`.
- **A bare ID.** The ID alone, such as `1qo6sai`. It must have 4 letters or
  numbers, or more.

You can mix all four in one run. A post that you list two times is read once.

- **Not found.** A post that does not exist or is removed. The log shows
  `Skipping post` and the ID, and the other posts still run. If no post can be
  read, the run still ends with the status **Succeeded** and an empty dataset.
- **Not a post.** An entry that has none of the four forms. The log shows how many
  entries were skipped, and the other posts still run.
- **No usable entry.** If none of your entries is a post reference, the run fails
  with a message that names `postUrls`.

### Choose the comments

#### How many comments

`maxCommentsPerPost` sets the most comments for each post. `0`, the default, gets
the whole thread.

With a limit, the Actor keeps the comments level by level. The top-level comments
come first, in the order of the sort. Then come the replies to them, then the
next level, until the limit is reached. This way every comment that you get has
its parent in the dataset too.

#### Comment order

`commentSort` sets the sort that Reddit uses for the comment tree.

| Value | Order |
|---|---|
| `confidence` | Best. This is the Reddit default. |
| `top` | Highest score first. |
| `new` | Newest first. |
| `controversial` | Most divided votes first. |
| `old` | Oldest first. |
| `qa` | The Q\&A sort of Reddit. |

The sort changes which comments you reach first. It also changes which comments
you can reach in a very large thread. Read [How many comments can I
get?](#how-many-comments-can-i-get) before you collect a thread with more than
10,000 comments.

#### Saving order

The dataset has the post first. Then come its comments. A parent comment is
always saved before its replies.

### Input reference

| Field | Type | Default | Description |
|---|---|---|---|
| `postUrls` | string\[] | required | Post URLs, `redd.it` links, `t3_` fullnames, or bare post IDs. At least one entry. |
| `maxCommentsPerPost` | integer | `0` | Maximum comments for each post, with all replies counted. `0` gets every comment. |
| `commentSort` | string | `confidence` | `confidence`, `top`, `new`, `controversial`, `old`, or `qa`. |
| `depth` | string | `basic` | `basic` or `detailed`. `detailed` adds the HTML text of the post and of each comment. |
| `proxyConfiguration` | object | Apify Proxy on | Proxy settings managed by Apify. |

Unknown input fields are ignored. Apify rejects a value of the wrong type before
the run starts. Examples are an empty `postUrls` list, a negative
`maxCommentsPerPost`, and a `commentSort` that is not in the list above.

<details>
<summary>Complete input example</summary>

This valid input shows how the fields fit together:

```json
{
  "postUrls": [
    "https://www.reddit.com/r/MachineLearning/comments/1qo6sai/",
    "t3_1rc3nez"
  ],
  "maxCommentsPerPost": 0,
  "commentSort": "confidence",
  "depth": "basic",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

</details>

### Output

The dataset has two kinds of item. A post has `type` set to `post`. A comment has
`type` set to `comment`. A comment is never inside a post, so a thread of any size
fits in the dataset.

Each comment has three fields that give the thread:

| Field | Meaning |
|---|---|
| `linkId` | The fullname of the post, such as `t3_1qo6sai`. It is the same for every comment of a post. |
| `parentId` | The fullname of the item above. It is the post for a top-level comment. It is another comment, such as `t1_o1z5yr1`, for a reply. |
| `depth` | The level of the comment. A top-level comment has `0`. A reply to it has `1`. |

To rebuild the tree, group the comments by `parentId`.

#### Fields by topic

- **Post.** ID, title, text, link, domain, and permalink.
- **Subreddit.** Name, ID, type, and subscriber count.
- **Author.** Name, ID, flair, and the Premium flag.
- **Votes and counts.** Score, upvote ratio, comment count, crosspost count, and
  award count.
- **Dates.** The created time as a UTC number and as an ISO 8601 string, and the
  edit time.
- **Flags.** Over 18, spoiler, stickied, locked, archived, quarantine, and
  distinguished.
- **Flair.** Text, type, CSS class, and colors of the post flair.
- **Media.** Thumbnail, preview images, gallery images, and video with HLS and
  DASH links.
- **Thread.** The post ID, the parent ID, and the depth of a comment.
- **Run.** The UTC time at which the Actor saved the post.

#### Post example

Square brackets mark values removed from the documentation.

<details>
<summary>Open the post JSON</summary>

```json
{
  "type": "post",
  "id": "1qo6sai",
  "fullName": "t3_1qo6sai",
  "subreddit": "MachineLearning",
  "subredditPrefixed": "r/MachineLearning",
  "subredditId": "t5_2r3gv",
  "subredditType": "public",
  "subredditSubscribers": 3078638,
  "title": "[D] Some thoughts about an elephant in the room no one talks about",
  "author": "[post author]",
  "authorFullName": "[author ID]",
  "authorFlairText": null,
  "authorFlairType": "text",
  "authorFlairCssClass": null,
  "authorPremium": false,
  "permalink": "https://www.reddit.com/r/MachineLearning/comments/1qo6sai/d_some_thoughts_about_an_elephant_in_the_room_no/",
  "url": "https://www.reddit.com/r/MachineLearning/comments/1qo6sai/d_some_thoughts_about_an_elephant_in_the_room_no/",
  "domain": "self.MachineLearning",
  "isSelf": true,
  "selftext": "[post text]",
  "selftextHtml": null,
  "score": 499,
  "upvoteRatio": 0.98,
  "numComments": 100,
  "numCrossposts": 2,
  "viewCount": null,
  "totalAwardsReceived": 0,
  "createdUtc": 1769497336,
  "created": "2026-01-27T07:02:16.000Z",
  "editedUtc": null,
  "edited": false,
  "over18": false,
  "spoiler": false,
  "stickied": false,
  "locked": false,
  "isVideo": false,
  "isOriginalContent": false,
  "contestMode": false,
  "archived": false,
  "quarantine": false,
  "distinguished": null,
  "removedByCategory": null,
  "linkFlairText": "Discussion",
  "linkFlairType": "text",
  "linkFlairCssClass": null,
  "linkFlairBackgroundColor": "#26c4d9",
  "linkFlairTextColor": "dark",
  "thumbnail": "self",
  "thumbnailWidth": null,
  "thumbnailHeight": null,
  "postHint": null,
  "previewImages": [],
  "galleryImages": [],
  "video": null,
  "crosspostParentId": null,
  "scrapedAt": "2026-10-23T21:26:58.702Z"
}
```

</details>

#### Comment example

This comment is a reply at depth `1`. Its `parentId` is another comment.

<details>
<summary>Open the comment JSON</summary>

```json
{
  "type": "comment",
  "id": "o1zcsgn",
  "fullName": "t1_o1zcsgn",
  "parentId": "t1_o1z5yr1",
  "linkId": "t3_1qo6sai",
  "subreddit": "MachineLearning",
  "subredditId": "t5_2r3gv",
  "author": "[commenter]",
  "authorFullName": "[author ID]",
  "authorFlairText": null,
  "authorPremium": false,
  "body": "Human nature, as soon as a benchmark is created the focus becomes laser focused on showing that 1% of improvement no matter what. [...]",
  "bodyHtml": null,
  "score": 75,
  "controversiality": null,
  "totalAwardsReceived": 0,
  "createdUtc": 1769501861,
  "created": "2026-01-27T08:17:41.000Z",
  "editedUtc": null,
  "edited": false,
  "depth": 1,
  "permalink": "https://www.reddit.com/r/MachineLearning/comments/1qo6sai/d_some_thoughts_about_an_elephant_in_the_room_no/o1zcsgn/",
  "isSubmitter": false,
  "stickied": false,
  "distinguished": null,
  "scoreHidden": false,
  "collapsed": false,
  "collapsedReasonCode": null
}
```

</details>

#### Field notes

- `id` is the Reddit ID. Use it to remove the comments that you already have, for
  example when you run a monitor on a schedule.
- `fullName` has a prefix. `t3_` is a post. `t1_` is a comment.
- `createdUtc` is a Unix time in seconds. `created` is the same time in ISO 8601.
- `selftext` and `body` have the plain text. `selftextHtml` and `bodyHtml` are
  `null` unless `depth` is `detailed`.
- `numComments` is the count that Reddit shows for the post. It can be larger than
  the number of comments that the run saves. See the FAQ.
- `isSubmitter` is `true` when the comment author is the author of the post.
- `scoreHidden` is `true` when the subreddit hides the score of new comments.
- `controversiality` is `null` when Reddit does not give it.

### FAQ

#### How many comments can I get?

The Actor saves every comment that Reddit shows for the post. With `0`, there is
no limit from the Actor.

Your count can be smaller than `numComments`, for two reasons:

- `numComments` counts the comments that moderators or users removed, and Reddit
  does not show them. In one test, a post had `numComments` of 100 and Reddit
  showed 83 comments.
- Reddit does not show all of a very large thread under one sort. In one test, a
  post had 18,787 comments in its count. The `confidence` sort gave about 14,000.
  Each other sort gave a different part, and the six sorts together gave about
  17,000.

To reach more comments of a very large thread, run it again with another
`commentSort`. Join the results on `id` to remove the duplicates.

#### Why did I get fewer comments than `maxCommentsPerPost`?

`maxCommentsPerPost` is an upper limit. The post can have fewer comments than the
limit. See the answer above.

#### The log says "Reddit did not load N more comment(s)". What does it mean?

Reddit did not answer the request for some part of the thread. The Actor tries
again several times and slows down before it gives up on that part. The comments
that Reddit showed are in the dataset. Run the post again to get the rest.

#### How long does a run take?

The time depends on the shape of the thread. A thread of 15,289 comments took
about 2 minutes with the default Apify Proxy. A thread with very long reply chains
is slower, because each chain needs its own request. In our slowest test, the
Actor saved about 8 comments each second.

A run stops at the run timeout in the run options. The comments that the Actor
saved before the stop stay in the dataset.

#### Does it use a lot of memory?

No. A run of 15,289 comments used about 170 MB.

#### Do I need a proxy?

The Actor uses Apify Proxy by default. A proxy lets many requests run at the same
time, and this makes large threads much faster. Without a proxy, large threads are
slow.

#### How do I get only the new comments?

The Actor has no date filter. Run it on a schedule with `commentSort` set to `new`
and a limit that is larger than the number of new comments between two runs.
Remove the comments that you already have with the `id` field, or keep the
comments with a `created` time after your last run.

#### Can I find posts by keyword, subreddit, or user?

No. This Actor needs the post URL or ID. To find posts by keyword, subreddit, or
user, use [Reddit Scraper](https://apify.com/kaix/reddit-scraper).

#### Is this the same as the post mode of Reddit Scraper?

The input fields are the same: `postUrls`, `commentSort`, `maxCommentsPerPost`,
`depth`, and `proxyConfiguration`. The output has the same fields. Fields that
this Actor does not use, such as `mode`, are ignored, so an old input still runs.
One default is different. `maxCommentsPerPost` is `0` here, so you get the whole
thread unless you set a limit.

#### A feature or field that I need is missing. What can I do?

Tell us in the **Issues** tab. Describe what you need and give an example post.

#### Where can I report a problem?

Open an issue in the **Issues** tab. Include the run ID and the input, so that we
can reproduce it.

### Similar Actors

- [Reddit Scraper](https://apify.com/kaix/reddit-scraper). Reddit posts by
  keyword, subreddit, or user, subreddit discovery, and post comments.
- [Yelp Reviews Scraper](https://apify.com/kaix/yelp-reviews-scraper). Yelp
  reviews and business data from business URLs, aliases, or IDs.
- [Trustpilot Reviews Scraper](https://apify.com/kaix/trustpilot-reviews-scraper).
  Trustpilot business reviews, with company replies, from business URLs or
  domains.
- [Google Maps Reviews Scraper](https://apify.com/kaix/google-maps-reviews-scraper).
  Google Maps reviews with place context, from place URLs or Place IDs.
- [TripAdvisor Reviews](https://apify.com/kaix/tripadvisor-reviews-scraper).
  TripAdvisor reviews of restaurants, hotels, attractions, and cruises.
- [Glassdoor Reviews Scraper](https://apify.com/kaix/glassdoor-reviews-scraper).
  Glassdoor company reviews with ratings, pros and cons, and employer responses.
- [Yellow Pages Reviews Scraper](https://apify.com/kaix/yellowpages-reviews-scraper).
  Reviews of Yellow Pages businesses in the US, UK, and Canada.

# Actor input Schema

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

The posts to scrape. Accepts full post URLs, redd.it short links, <code>t3\_</code> fullnames, or bare post IDs. Each post is saved, then all of its comments.

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

Cap on comments saved per post, counting nested replies. Set to 0 to collect the complete thread, down to the last reply. Comments are saved while they load.

## `commentSort` (type: `string`):

The sort order Reddit uses for the comment tree. Reddit shows only part of a very large thread under any one sort, so the sort also decides which comments you can reach.

## `depth` (type: `string`):

Basic: core fields, images and video. Detailed: adds the HTML body of the post and of each comment.

## `proxyConfiguration` (type: `object`):

Proxy settings for the run. Apify proxy is on by default and helps large threads finish sooner. Switch it off to run without one.

## Actor input object example

```json
{
  "postUrls": [
    "https://www.reddit.com/r/MachineLearning/comments/1qo6sai/"
  ],
  "maxCommentsPerPost": 0,
  "commentSort": "confidence",
  "depth": "basic",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (type: `string`):

All collected posts and comments as JSON. Filter on the type field. Append ?format=csv or ?format=xlsx to download a spreadsheet.

## `posts` (type: `string`):

The posts table view: type, subreddit, title, author, score, upvote ratio, comment count, posting time, and URL.

## `comments` (type: `string`):

The comments table view: type, post, parent, depth, author, score, text, posting time, and URL.

# 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/MachineLearning/comments/1qo6sai/"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kaix/reddit-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/MachineLearning/comments/1qo6sai/"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("kaix/reddit-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/MachineLearning/comments/1qo6sai/"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call kaix/reddit-comments-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kaix/reddit-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/lqcPQ6W3Jw0sPEVD1/builds/x5oe1eRWwBwYQxW1B/openapi.json
