# YouTube Comments Scraper – Comments & Replies (`arjun_code/youtube-comments-scraper`) Actor

Scrape YouTube comments and replies from videos and Shorts. Export text, authors, likes, timestamps, pinned comments, and direct links without an API key.

- **URL**: https://apify.com/arjun\_code/youtube-comments-scraper.md
- **Developed by:** [Arjun AI](https://apify.com/arjun_code) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 youtube comment or replies

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### Export YouTube comments and replies

Turn public discussions from YouTube videos and Shorts into structured records. Add up to 20 URLs and receive one Dataset item per parent comment or reply, with comment text, authors, likes, timestamps, reply relationships, pinned status, creator hearts, membership badges, paid-comment indicators, and direct comment URLs.

Choose **Top comments** for a ranked sample, **Newest first** for chronological collection, or set the limit to `0` to traverse all public comment pages YouTube makes available. No YouTube Data API key is required.

Videos that cannot produce comment rows receive a visible, free `videoStatus` record, so an empty Dataset is not mistaken for a broken run.

> This is an unofficial Actor and is not affiliated with, endorsed by, or sponsored by YouTube or Google. It collects publicly accessible comments only.

### Ready-to-run examples

- [Analyze top YouTube comments](https://apify.com/arjun_code/youtube-comments-scraper/examples/analyze-top-youtube-comments)
- [Download all public YouTube comments](https://apify.com/arjun_code/youtube-comments-scraper/examples/download-all-public-youtube-comments)
- [Scrape YouTube comments and replies](https://apify.com/arjun_code/youtube-comments-scraper/examples/scrape-youtube-comments-and-replies)
- [Scrape YouTube Shorts comments](https://apify.com/arjun_code/youtube-comments-scraper/examples/scrape-youtube-shorts-comments)

### Common use cases

- Brand, product, and campaign monitoring
- Audience research and creator analysis
- Sentiment, topic, and keyword analysis
- Community feedback and moderation review
- Market research and competitor tracking
- NLP, LLM, and data-enrichment workflows

### Supported URLs

| URL type | Example |
| --- | --- |
| Standard video | `https://www.youtube.com/watch?v=VIDEO_ID` |
| Short link | `https://youtu.be/VIDEO_ID` |
| Shorts | `https://www.youtube.com/shorts/VIDEO_ID` |
| Embedded video | `https://www.youtube.com/embed/VIDEO_ID` |
| Live video page | `https://www.youtube.com/live/VIDEO_ID` |

For live video pages, the Actor extracts the normal public comments section when available. It does not extract live-chat messages.

### Quick start

This input returns up to 100 ranked parent comments:

```json
{
  "startUrls": [
    {
      "url": "https://www.youtube.com/watch?v=YE7VzlLtp-4"
    }
  ],
  "maxCommentsPerVideo": 100,
  "sortBy": "top",
  "includeReplies": false,
  "maxRepliesPerThread": 10
}
```

### Input reference

| Field | Type | Default | Behavior |
| --- | --- | --- | --- |
| `startUrls` | array | Required | 1–20 public video or Shorts URLs. Duplicate video IDs are processed once. |
| `maxCommentsPerVideo` | integer | `100` | `1–5000` limits combined parent and reply records per video. `0` requests all available public comment pages. |
| `sortBy` | string | `top` | `top` for YouTube's ranked view or `newest` for chronological results. Full collection always uses `newest`. |
| `includeReplies` | boolean | `false` | Expand and return replies under each parent comment. Disable for the fastest parent-only run. |
| `maxRepliesPerThread` | integer | `10` | 1–500 replies per parent when `includeReplies` is enabled. It has no effect when replies are disabled. |

#### Sorting and full collection

| Result limit | Requested sort | Effective sort | Result |
| ---: | --- | --- | --- |
| Positive number | `top` | `top` | Fixed-size ranked sample |
| Positive number | `newest` | `newest` | Fixed-size chronological sample |
| `0` | `top` or `newest` | `newest` | All available public comment pages |

To collect all available parent comments and replies:

```json
{
  "startUrls": [
    {
      "url": "https://www.youtube.com/watch?v=VIDEO_ID"
    }
  ],
  "maxCommentsPerVideo": 0,
  "sortBy": "newest",
  "includeReplies": true,
  "maxRepliesPerThread": 500
}
```

`maxCommentsPerVideo: 0` removes the combined result limit, but `maxRepliesPerThread` still limits each reply thread. “All” means all comments YouTube exposes to a public, unauthenticated session—not private, deleted, held-for-review, or otherwise unavailable comments.

### Dataset output

Each parent comment and included reply is a separate `recordType: "comment"` item.

#### Real comment example

This shortened record came from a real run. Public counters and relative dates can change.

```json
{
  "recordType": "comment",
  "sourceType": "video",
  "videoId": "YE7VzlLtp-4",
  "videoUrl": "https://www.youtube.com/watch?v=YE7VzlLtp-4",
  "videoTitle": "Big Buck Bunny",
  "videoChannelName": "Blender",
  "commentId": "UgyvM3zp3TKN8kEO4Yd4AaABAg",
  "commentUrl": "https://www.youtube.com/watch?v=YE7VzlLtp-4&lc=UgyvM3zp3TKN8kEO4Yd4AaABAg",
  "text": "still looks better than my renders",
  "publishedTimeText": "3 years ago",
  "publishedAtEstimated": "2023-08-31T06:21:28.917413Z",
  "likeCount": 498,
  "likeCountText": "498",
  "replyCount": 5,
  "parentCommentId": null,
  "replyDepth": 0,
  "isReply": false,
  "isPinned": false,
  "isHearted": false,
  "isPaid": false,
  "authorName": "@5MadMovieMakers",
  "authorChannelId": "UCLkZVEXz_qObWr7hAEbS_pQ",
  "authorChannelUrl": "https://www.youtube.com/@5MadMovieMakers",
  "authorIsVerified": true,
  "authorIsVideoOwner": false,
  "authorIsMember": false,
  "authorBadges": [
    "Verified"
  ],
  "sortBy": "top"
}
```

#### Field groups

| Group | Fields |
| --- | --- |
| Source | `recordType`, `sourceType`, `videoId`, `videoUrl`, `videoTitle`, `videoChannelId`, `videoChannelName` |
| Comment | `commentId`, `commentUrl`, `text`, `publishedTimeText`, `publishedAtEstimated` |
| Engagement | `likeCount`, `likeCountText`, `replyCount`, `isPinned`, `isHearted`, `isPaid`, `paidAmountText` |
| Reply relationship | `parentCommentId`, `replyDepth`, `isReply` |
| Author | `authorName`, `authorChannelId`, `authorChannelUrl`, `authorAvatarUrl`, `authorIsVerified`, `authorIsVideoOwner`, `authorIsMember`, `authorBadges` |
| Run context | `sortBy`, `scrapedAt` |

`publishedAtEstimated` is calculated from YouTube's relative label such as `3 years ago`. It is useful for sorting, but it is not an exact publication timestamp supplied by YouTube. `likeCount` is normalized from the displayed value; `likeCountText` preserves the public label.

#### Reply records

A reply has `isReply: true`, `replyDepth: 1`, and its parent's ID in `parentCommentId`. Every reply is independently written to the Dataset and counts as one successful comment result.

#### Videos without comment rows

When comments are empty, disabled, unavailable, partially extracted, failed, or stopped by the maximum charge, the Dataset receives a free status record:

```json
{
  "recordType": "videoStatus",
  "status": "noComments",
  "inputValue": "https://www.youtube.com/watch?v=VIDEO_ID",
  "sourceType": "video",
  "videoId": "VIDEO_ID",
  "commentCount": 0,
  "parentCommentCount": 0,
  "replyCommentCount": 0,
  "truncated": false,
  "errorCode": "NO_PUBLIC_COMMENTS",
  "errorMessage": "No public comments were returned for this video.",
  "suggestion": "No action is required. Verify the public comment section if comments were expected."
}
```

Possible status values are `noComments`, `commentsDisabled`, `unavailable`, `partial`, `failed`, and `chargeLimitReached`.

### Pricing

This Actor uses pay-per-event pricing:

- **Actor start:** `$0.00005` per run.
- **Comment or reply result:** `$0.0005` each—`$0.50` per 1,000 results.
- **Video status row:** free.

Example event charges before any configured discounts:

| Comment and reply records | Event charge including one start |
| ---: | ---: |
| 1 | `$0.00055` |
| 100 | `$0.05005` |
| 1,000 | `$0.50005` |

The Actor respects the user's maximum run charge. If the budget cannot cover another comment result, collection stops and the input receives a free `chargeLimitReached` status. The **Pricing** tab is the source of truth for current prices and discounts.

### Run summary

The Dataset is the primary output. The default Key-Value Store record named `OUTPUT` is a compact run report for automation and troubleshooting. It contains totals plus a status for every input video, including successful, empty, disabled, unavailable, partial, failed, and charge-limited sources.

Use it when a source produced no comment records and you need to distinguish “no public comments” from “request failed.”

### Run through the Apify API

For small runs, the synchronous endpoint returns Dataset items directly:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/arjun_code~youtube-comments-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startUrls": [{"url": "https://www.youtube.com/watch?v=YE7VzlLtp-4"}],
    "maxCommentsPerVideo": 100,
    "sortBy": "top",
    "includeReplies": false,
    "maxRepliesPerThread": 10
  }'
```

For large full-collection runs, start the Actor asynchronously and read the default Dataset after completion.

### Performance guidance

- Start with 10–100 comments when evaluating a source.
- Leave replies disabled if you only need parent comments.
- Use `0` only when complete public pagination is required; popular videos can contain many pages.
- Up to three videos are processed concurrently. Pages for one video remain sequential because YouTube continuation tokens must be followed in order.

### Troubleshooting

#### The Dataset contains only a status row

Read `status`, `errorMessage`, and `suggestion`. A video may genuinely have no comments, have comments disabled, be unavailable to a public session, or encounter a temporary request failure.

#### The collected total is lower than YouTube's displayed count

Displayed totals can include deleted, hidden, moderated, unavailable, or non-public comments. Replies are also capped by `maxRepliesPerThread`. The Actor stops when YouTube no longer provides a public continuation token.

#### `includeReplies` is false—does `maxRepliesPerThread` matter?

No. The setting is ignored until replies are enabled.

### Related Actors

| Goal | Actor |
| --- | --- |
| Discover videos, Shorts, or channels by keyword | [YouTube Search Scraper](https://apify.com/arjun_code/youtube-search-scraper) |
| Get metadata for known video or Shorts URLs or IDs | [YouTube Video and Shorts Details Scraper](https://apify.com/arjun_code/youtube-video-details-scraper) |
| Enrich known channel handles, IDs, or URLs | [YouTube Channel Details Scraper](https://apify.com/arjun_code/youtube-channel-details-scraper) |
| Export a channel's videos, Shorts, and streams | [YouTube Channel Content Scraper](https://apify.com/arjun_code/youtube-channel-content-scraper) |

### FAQ

#### Does Top comments return every comment?

No. It is YouTube's ranked view. Set `maxCommentsPerVideo` to `0`; the Actor automatically uses Newest first for the most complete public collection.

#### Does this support Shorts?

Yes. Supply a `/shorts/VIDEO_ID` URL. The output uses `sourceType: "short"`.

#### Does this require a YouTube API key?

No.

#### Can it scrape private comments or live chat?

No. It returns comments visible to a public, unauthenticated visitor. It does not access private data, creator dashboards, held-for-review comments, or live chat.

### Support and responsible use

For unexpected results, open the Actor's **Issues** tab and include the run ID, public video URL, input settings, expected behavior, and relevant status or log message. Do not post API tokens or private data.

Use the Actor only for lawful processing of publicly accessible information. Follow applicable laws, privacy requirements, and YouTube's terms. Do not use the output for spam, harassment, or invasive profiling.

# Actor input Schema

## `startUrls` (type: `array`):

Supports youtube.com/watch, youtu.be, youtube.com/shorts, youtube.com/embed, and youtube.com/live URLs.

## `maxCommentsPerVideo` (type: `integer`):

Maximum Dataset records returned per video. Set to 0 to load every available public comment page; full collection mode automatically uses Newest first. Parent comments and included replies both count when a positive limit is used.

## `sortBy` (type: `string`):

Choose Top comments for a ranked sample or Newest first for chronological results. When Maximum comments per video is 0, the Actor automatically uses Newest first for the most complete collection.

## `includeReplies` (type: `boolean`):

Expand replies below each parent comment. Leave disabled for the fastest run.

## `maxRepliesPerThread` (type: `integer`):

Maximum replies extracted from each parent comment when Include replies is enabled.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.youtube.com/watch?v=YE7VzlLtp-4"
    }
  ],
  "maxCommentsPerVideo": 100,
  "sortBy": "top",
  "includeReplies": false,
  "maxRepliesPerThread": 10
}
```

# Actor output Schema

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

No description

## `summary` (type: `string`):

No description

# 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 = {
    "startUrls": [
        {
            "url": "https://www.youtube.com/watch?v=YE7VzlLtp-4"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("arjun_code/youtube-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 = { "startUrls": [{ "url": "https://www.youtube.com/watch?v=YE7VzlLtp-4" }] }

# Run the Actor and wait for it to finish
run = client.actor("arjun_code/youtube-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 '{
  "startUrls": [
    {
      "url": "https://www.youtube.com/watch?v=YE7VzlLtp-4"
    }
  ]
}' |
apify call arjun_code/youtube-comments-scraper --silent --output-dataset

```

## MCP server setup

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