# YouTube Comments Scraper (`thenetaji/youtube-comments-scraper`) Actor

Collect comments from YouTube videos, Shorts, and community posts. Process multiple URLs or IDs, choose Top or Newest order, paginate automatically, and optionally attach parent content details.

- **URL**: https://apify.com/thenetaji/youtube-comments-scraper.md
- **Developed by:** [The Netaji](https://apify.com/thenetaji) (community)
- **Categories:** Social media, Videos, For creators
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.45 / 1,000 results

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

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## YouTube Comments Scraper

The Actor collects public comments from YouTube videos, Shorts, and community posts. It accepts a mixed list of targets as URLs or IDs, detects which kind each one is, paginates through the comment thread, and can optionally attach the parent video or post to every comment it saved. No YouTube account, API key, or cookie is required.

### Accepted input

| Field | Type | Default | Description |
|---|---|---|---|
| `comment_sources` | array | — | Required. Video, Shorts, or community-post URLs or IDs. |
| `maxItems` | integer | `100` | Maximum comments saved across all targets. `0` removes the limit. |
| `sort_order` | enum | `top` | `top` for YouTube's ranking, `newest` for most recent first. |
| `includeParentDetails` | boolean | `false` | Attaches the parent video or post to each comment. |
| `owner_channel` | string | — | Channel ID owning a community post, when the post is given as a bare ID. |
| `region_code` | string | `US` | Two-letter country code used to localize results. |
| `language_code` | string | `en` | Language code for result text. |

```json
{
  "comment_sources": [
    { "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" },
    { "url": "https://www.youtube.com/shorts/P4-3XTiiogo" }
  ],
  "sort_order": "top",
  "maxItems": 500
}
```

### Response fields

One row per comment.

| Field | Contents |
|---|---|
| `recordType` | `video_comment` or `post_comment` |
| `source` | The target the comment came from, as supplied |
| `commentId` | YouTube comment ID |
| `textDisplay` | Comment body as displayed |
| `authorText` | Author's display name |
| `authorChannelId`, `authorChannelHandle` | Author's channel |
| `authorThumbnail` | Author avatar |
| `authorIsChannelOwner` | Whether the author owns the video's channel |
| `likesCount` | Reported likes on the comment |
| `replyCount` | Reported replies to the comment |
| `publishedTimeText`, `publishedAt`, `publishDate` | Relative time, ISO 8601 timestamp, and date |
| `isVerified`, `isArtist`, `isCreator` | Author badges YouTube displays |
| `position` | One-based position within the run |
| `meta` | Thread context, including the reported total comment count |
| `parentDetails` | The parent video or post, with `includeParentDetails` |

```json
{
  "recordType": "video_comment",
  "commentId": "Ugzge340dBgB75hWBm54AaABAg",
  "textDisplay": "can confirm: he never gave us up",
  "authorText": "@YouTube",
  "authorChannelHandle": "@YouTube",
  "publishedTimeText": "1 year ago",
  "publishDate": "2025-07-30",
  "position": 1
}
```

Note that a comment's like count is `likesCount` while a video's is `likeCount`. That inconsistency is YouTube's; the field names are left as returned rather than renamed, so they match the saved rows.

### Targets, and how each kind is detected

A target is read as a community post when it is a `/post/` URL or a bare ID beginning `Ug`, and as a video otherwise. Videos and Shorts use the same comment thread, so a Shorts URL needs no special handling.

Community posts given as a bare post ID may also need `owner_channel`, the `UC…` ID of the channel that published the post. Posts supplied as full URLs do not.

### Pagination and result limits

Comments are collected in pages of about 20 and the cursor is followed until `maxItems` is reached, YouTube stops serving pages, or a cursor repeats. `maxItems` is a budget shared across every target in the run: with three videos and `maxItems: 100`, the first video may consume most of it. Run targets separately when even coverage across them matters.

`meta` carries YouTube's own reported comment count for the thread, which is useful for judging what fraction of a discussion was collected. That count includes replies, while the collected rows are top-level comments, so it will normally exceed the number of rows saved.

### Behaviour on partial results

A target that cannot be parsed is logged and skipped. A target whose comments YouTube declines to serve — comments disabled, or a post that is not publicly readable — is logged and skipped, and the remaining targets still run. Comments already collected are kept. The run fails only when no supplied target was a usable reference.

`includeParentDetails` is fetched once per target rather than once per comment, and the resulting object is attached to every comment from that target. It is charged once per target on success. A failure leaves the field absent, is not charged, and does not stop the comments from being collected.

### Frequently asked questions

**Are replies collected as well as top-level comments?**
Top-level comments are collected. `replyCount` records how many replies each one has, so threads worth expanding are identifiable, but the replies themselves are not saved as rows.

**Why did a video return no comments?**
Most often comments are disabled on it, which YouTube reports as an empty thread rather than an error. The run log names the target. It is also possible the thread is genuinely empty — a newly published video, or a community post nobody has replied to.

**What is the difference between `top` and `newest`?**
`top` is YouTube's own ranking, which weights engagement and tends to surface the same well-liked comments the site shows first. `newest` is strictly reverse-chronological. For sampling opinion, `top` is more representative of what viewers actually see; for monitoring, `newest` is more useful.

**Can every comment on a large video be collected?**
Only as far as YouTube keeps serving pages. Threads with millions of comments are not served in full to anyone, including the site itself. Set `maxItems: 0` to take everything offered and treat the result as a large sample rather than a census.

**Why is `authorThumbnail` sometimes a single URL and sometimes a list?**
Comments return one avatar URL; community posts return several sizes. Both are passed through as returned rather than normalised into one shape.

**Is a YouTube account or API key required?**
No. Only publicly visible comments are read, with no credentials or logged-in session, and no YouTube Data API quota is consumed.

### Related Actors

| Actor | Purpose |
|---|---|
| [YouTube Video Scraper](https://apify.com/thenetaji/youtube-video-scraper) | Full metadata and transcripts for known videos and Shorts |
| [YouTube Channel Scraper](https://apify.com/thenetaji/youtube-channel-scraper) | Channel details, uploads, and community posts |
| [YouTube Search Scraper](https://apify.com/thenetaji/youtube-search-scraper) | Find videos by keyword, hashtag, or chart |
| [YouTube Playlist Scraper](https://apify.com/thenetaji/youtube-playlist-scraper) | Playlist metadata and every video in it |

# Actor input Schema

## `comment_sources` (type: `array`):

One or more public YouTube videos, Shorts, or community posts whose comments should be collected.

## `owner_channel` (type: `string`):

Optional channel ID that owns a community post. Use it when providing a bare post ID.

## `includeParentDetails` (type: `boolean`):

Attach video, Shorts, or community-post details to comments from the same target. One extra request per target, charged only when it succeeds.

## `maxItems` (type: `integer`):

Maximum number of primary records to save across all targets. Set 0 to continue until no more pages remain.

## `sort_order` (type: `string`):

Order the returned results. The available values depend on the workflow.

## `region_code` (type: `string`):

Optional two-letter country code used to localize results, such as US, IN, or DE.

## `language_code` (type: `string`):

Optional language code used to localize result text, such as en, es, or pt-BR.

## Actor input object example

```json
{
  "comment_sources": [
    {
      "url": "https://www.youtube.com/watch?v=aqz-KE-bpKQ"
    }
  ],
  "owner_channel": "UCAuUUnT6oDeKwE6v1NGQxug",
  "includeParentDetails": false,
  "maxItems": 20,
  "sort_order": "top",
  "region_code": "US",
  "language_code": "en"
}
```

# Actor output Schema

## `dataset` (type: `string`):

All records scraped by this run

# 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 = {
    "comment_sources": [
        {
            "url": "https://www.youtube.com/watch?v=aqz-KE-bpKQ"
        }
    ],
    "maxItems": 20,
    "region_code": "US"
};

// Run the Actor and wait for it to finish
const run = await client.actor("thenetaji/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 = {
    "comment_sources": [{ "url": "https://www.youtube.com/watch?v=aqz-KE-bpKQ" }],
    "maxItems": 20,
    "region_code": "US",
}

# Run the Actor and wait for it to finish
run = client.actor("thenetaji/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 '{
  "comment_sources": [
    {
      "url": "https://www.youtube.com/watch?v=aqz-KE-bpKQ"
    }
  ],
  "maxItems": 20,
  "region_code": "US"
}' |
apify call thenetaji/youtube-comments-scraper --silent --output-dataset

```

## MCP server setup

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