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

🔥 $0.15/1K comments 🔥 Extract comments, replies, authors, likes, timestamps, pinned and hearted status. Sort by Top or Newest, filter by date, and export clean JSON, CSV or Excel. Fast YouTube Comments Scraper API for one or multiple videos and Shorts.

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

## Pricing

from $0.05 / 1,000 searches

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

## YouTube Comments Scraper

Extract public comments from one or many YouTube videos **and Shorts** and turn them into clean, structured data. This **YouTube comments scraper** collects comment text, authors, likes, reply counts, publish dates, pinned and hearted status, and optional reply threads.

Use the Actor in the Apify Console or connect it to your workflow through the **YouTube comments scraper API**. Results are saved to an Apify dataset for download, filtering, analysis, or automated processing.

> **No limits, no quotas.** This Actor has no request limits, comment caps, or hard quotas. You can scrape a single video or hundreds, one comment or as many as a video holds — every comment, every reply.

### What can this YouTube comments scraper do?

This Actor can:

- Collect public comments from a YouTube video ID or full URL — **including YouTube Shorts**.
- Process multiple videos and Shorts in a single run — scraped **concurrently** at ~12 requests/second for speed.
- Return the newest comments or YouTube's Top comments.
- Collect every available comment or stop at a limit you choose.
- Keep only comments published after an absolute or relative date.
- Fetch complete reply threads or limit the replies collected per comment.
- Save structured results to a dataset and a run summary under `OUTPUT`.

Each result includes the video ID, comment ID, author details, comment text, likes, replies, relative and exact publish times, moderation signals, and source feed. Comments and replies are supported for both **regular YouTube videos and Shorts**.

### 📤 What the Actor returns

The Actor writes **one dataset item per top-level comment** to the run's default dataset, and a short run summary to the key–value store under `OUTPUT`.

- **Dataset items** (one per top-level comment) — described in the section [YouTube comment data output](#youtube-comment-data-output). Each item has the fields below. When `replies: true`, replies are nested in each item's `replies` array (not separate dataset items).
- **`OUTPUT` summary** — `{ videos_requested, comments_pushed, replies_pushed, sort }`, written to the key–value store at the end of the run.

| Item | Where it is stored | Contents |
| --- | --- | --- |
| Comment record | default dataset | one per top-level comment (see fields below) |
| Replies (when enabled) | nested in each comment's `replies` array | one reply object per reply |
| Run summary | key–value store key `OUTPUT` | videos requested, comments pushed, sort order |

Each comment record contains:

| Field | Type | Description |
| --- | --- | --- |
| `video_id` | string | ID of the video the comment belongs to |
| `comment_id` | string | unique comment identifier |
| `author` | string | commenter display name (`@handle`) |
| `author_channel_id` | string | commenter's channel ID |
| `author_avatar` | string | author profile image URL |
| `author_is_channel_owner` | boolean | whether the author owns the channel |
| `text` | string | plain-text comment content |
| `published` | string | relative time, e.g. `2 minutes ago` |
| `published_at` | string | exact UTC publish time (ISO 8601) |
| `like_count` | integer | number of likes |
| `reply_count` | integer | number of replies under the comment |
| `is_pinned` | boolean | whether the channel pinned it |
| `pinned_by` | string | who pinned it, when known |
| `reply_level` | integer | `0` top-level, `1` reply |
| `is_hearted` | boolean | whether the channel owner hearted it |
| `replies` | array | reply records (only when `replies: true`) |
| `source` | string | `newest` or `top` feed the record came from |

### Common use cases

- **Audience research:** understand what viewers like, dislike, ask, or recommend.
- **Sentiment analysis:** prepare comment text for NLP, LLM, or BI workflows.
- **Brand monitoring:** find recurring feedback and discussions around products or campaigns.
- **Competitor research:** compare audience reactions across several videos.
- **Content strategy:** identify questions, objections, ideas, and high-engagement topics.
- **Community analysis:** study popular threads and conversations between viewers.
- **Comment archiving:** preserve public discussion data in JSON, CSV, Excel, or other Apify-supported formats.

### 📥 Input reference

| Input | Type | Default | Description |
| --- | --- | --- | --- |
| `videos` | array of strings | — | **Required.** One or more YouTube **video IDs or full URLs**, including **YouTube Shorts** (e.g. `https://youtube.com/shorts/VIDEOID`). |
| `limit` | integer | empty | Maximum number of comments to collect **per video**. Leave empty to collect everything the selected feed returns. |
| `sort` | `newest` or `top` | `newest` | Select YouTube's chronological Newest feed or its Top comments feed. |
| `published_after` | string | `0` | Keep comments published after a relative date such as `7 days` or an absolute date such as `2026-01-01`. Used only with `sort: "newest"`. |
| `replies` | boolean | `false` | Fetch replies for every returned top-level comment. |
| `max_replies` | integer | `0` | Maximum replies to collect per comment. `0` means all available replies. Used only when `replies` is `true`. |

### Input examples

Choose the example closest to your goal and adjust the values.

#### Get the newest 100 comments from one video

```json
{
  "videos": ["dQw4w9WgXcQ"],
  "sort": "newest",
  "limit": 100
}
```

#### Get comments from a YouTube Short

Pass a Short's full URL (or its video ID). Comments and replies are collected the same way as for regular videos.

```json
{
  "videos": ["https://youtube.com/shorts/VIDEOID"],
  "sort": "newest",
  "limit": 100
}
```

#### Scrape comments from several videos

The `limit` applies separately to each video.

```json
{
  "videos": ["dQw4w9WgXcQ", "9bZkp7q19f0"],
  "sort": "newest",
  "limit": 500
}
```

#### Collect every available comment

Leave out `limit` to continue until the selected YouTube feed has no more results.

```json
{
  "videos": ["dQw4w9WgXcQ"],
  "sort": "newest"
}
```

#### Get Top comments

```json
{
  "videos": ["dQw4w9WgXcQ"],
  "sort": "top",
  "limit": 200
}
```

#### Get comments from the last 7 days

```json
{
  "videos": ["dQw4w9WgXcQ"],
  "sort": "newest",
  "published_after": "7 days"
}
```

#### Get comments published after a fixed date

```json
{
  "videos": ["dQw4w9WgXcQ"],
  "sort": "newest",
  "published_after": "2026-01-01"
}
```

#### Get comments with all available replies

```json
{
  "videos": ["dQw4w9WgXcQ"],
  "sort": "newest",
  "replies": true,
  "max_replies": 0
}
```

#### Limit replies to 20 per comment

```json
{
  "videos": ["dQw4w9WgXcQ"],
  "sort": "newest",
  "replies": true,
  "max_replies": 20
}
```

#### Combine date filtering, replies, and multiple videos

```json
{
  "videos": ["dQw4w9WgXcQ", "9bZkp7q19f0"],
  "sort": "newest",
  "limit": 300,
  "published_after": "30 days",
  "replies": true,
  "max_replies": 10
}
```

### 🔌 YouTube Comments Scraper API

You can run the Actor programmatically with the Apify API. Send the same JSON input used in the Console and receive the dataset items in the response.

Replace `<ACTOR_ID>` and `<APIFY_API_TOKEN>` with the values shown in the Actor's **API** tab:

```bash
curl -X POST \
  "https://api.apify.com/v2/actors/<ACTOR_ID>/run-sync-get-dataset-items?token=<APIFY_API_TOKEN>&format=json&clean=true" \
  -H "Content-Type: application/json" \
  -d '{
    "videos": ["dQw4w9WgXcQ"],
    "sort": "newest",
    "limit": 100,
    "replies": true,
    "max_replies": 10
  }'
```

For large jobs, start the Actor asynchronously, monitor the run, and retrieve items from its default dataset after completion. This avoids keeping one HTTP connection open for a long-running scrape.

### 📤 YouTube comment data output

Each dataset item represents a top-level comment. When reply collection is enabled, its replies appear in the `replies` array.

```json
{
  "video_id": "dQw4w9WgXcQ",
  "comment_id": "Ugzge340dBgB75hWBm54AaABAg",
  "author": "@YouTube",
  "author_channel_id": "UCBR8-60-B28hp2BmDPdntcQ",
  "author_avatar": "https://yt3.ggpht.com/...",
  "author_is_channel_owner": true,
  "text": "This is the comment text.",
  "published": "1 year ago",
  "published_at": "2025-08-29T19:41:32Z",
  "like_count": 1234,
  "reply_count": 1000,
  "is_pinned": false,
  "pinned_by": "",
  "reply_level": 0,
  "is_hearted": false,
  "replies": [],
  "source": "newest"
}
```

#### Output fields explained

| Field | Description |
| --- | --- |
| `video_id` | ID of the YouTube video containing the comment. |
| `comment_id` | Unique YouTube comment identifier. |
| `author` | Commenter's display name, often shown as an `@handle`. |
| `author_channel_id` | YouTube channel ID associated with the author. |
| `author_avatar` | URL of the author's profile image. |
| `author_is_channel_owner` | Whether the author owns the video channel. |
| `text` | Plain-text content of the comment. |
| `published` | Relative publish time displayed by YouTube, such as `2 minutes ago`. |
| `published_at` | Exact UTC publish time in ISO 8601 format. |
| `like_count` | Number of likes shown on the comment. |
| `reply_count` | Number of replies shown under the top-level comment. |
| `is_pinned` | Whether the channel pinned the comment. |
| `pinned_by` | Name of the account that pinned the comment, when available. |
| `reply_level` | `0` for a top-level comment and `1` for a reply. |
| `is_hearted` | Whether the channel owner hearted the comment. |
| `replies` | Reply records collected when `replies` is enabled. |
| `source` | Feed used to retrieve the record: `newest` or `top`. |

#### Reply structure

Replies use the same core fields as top-level comments and have `reply_level: 1`.

```json
{
  "comment_id": "Ugzge340dBgB75hWBm54AaABAg",
  "reply_level": 0,
  "text": "Top-level comment",
  "replies": [
    {
      "comment_id": "Ugz...reply1",
      "author": "@someone",
      "text": "A reply to the comment.",
      "published_at": "2026-08-30T01:38:32Z",
      "like_count": 7,
      "reply_count": 0,
      "reply_level": 1
    }
  ]
}
```

#### Run summary in `OUTPUT`

The Actor stores a compact summary in the default key-value store:

```json
{
  "videos_requested": 2,
  "comments_pushed": 300,
  "replies_pushed": 120,
  "sort": "newest"
}
```

The run log also reports the collected totals and an estimated cost at the end,
e.g. `done: 300 comments, 120 replies (est. cost $0.1350 = $0.0750 comments +
$0.0600 replies)`, based on the suggested per-event prices.

### Export and integrate the results

Open the run's **Storage** tab to preview or download the dataset. Apify datasets can be exported in formats such as JSON, CSV, Excel, XML, and HTML.

You can also connect the results to databases, dashboards, AI pipelines, webhooks, scheduled tasks, or automation platforms supported by Apify.

### Important behavior and limitations

- **Comment totals:** YouTube's displayed total can include both top-level comments and replies. The main dataset contains top-level comments; replies are included only when `replies` is enabled.
- **Feed behavior:** The Top and Newest orderings come from YouTube. If the requested feed is unavailable, the Actor returns no results instead of silently switching to another order.
- **Date filtering:** `published_after` works with the chronological Newest feed. It is ignored when `sort` is set to `top`.
- **Public data:** The Actor collects publicly visible comments. Videos that are unavailable, restricted, deleted, or have comments disabled may not return data.
- **Concurrent scraping:** When you provide several videos, they're scraped in parallel — up to **12 videos at a time** (any extra videos queue and process as earlier ones finish), with the total request rate capped at ~12 requests/second. This keeps a batch run fast while staying inside the service's rate budget, and each video is processed independently — one unavailable video doesn't stop the rest. The video concurrency cap is configurable via the **`MAX_CONCURRENT_VIDEOS`** environment variable (default `12`; the Actor clamps it to 1–500).
- **Memory efficient:** Comments are streamed to the dataset batch-by-batch (100 at a time), not held in memory, and only a bounded number of videos are scraped at once. Peak memory stays flat no matter how many videos or comments you request, so it works on a small, low-RAM run (typically well under 128 MB).
- **Responsible use:** Follow applicable laws, YouTube's terms, and data-protection requirements when collecting or processing public comment data.

There is **no quota or cap imposed by the Actor itself** — you can request any number of videos or comments in a single run, and the Actor pages through what YouTube exposes. The only ceiling is what the platform returns for a given video (for example, how many comments YouTube makes available, or whether a video has comments enabled).

### Pricing

This Actor uses Apify's **pay-per-event (PPE)** monetization. Each comment
pushed to the default dataset is charged as `apify-default-dataset-item`
(billed automatically by Apify — no charging code needed). One **custom**
event is additionally charged from the Actor and must be configured in
**Apify Console → Actor → Publication → Monetization** (custom events → add):

| Event name | Description | Charged when | Suggested price |
| --- | --- | --- | ---: |
| `apify-default-dataset-item` | one per comment pushed | automatically, per dataset item | $0.00025 (=$0.25 / 1,000 comments) |
| `reply` | one per reply collected | per reply, when `Include replies` is on | $0.00050 (=$0.50 / 1,000 replies) |

Set a per-run spending limit, pick a **Primary event**, then review. Charging a
custom event that isn't configured is a safe no-op (it logs a warning and bills
nothing), so the `reply` event is an optional extra — the default
dataset-item charge always applies for every comment.

A flat monthly fee is another option when the Actor is offered as a
fixed-capacity service.

### Frequently asked questions

#### What is a YouTube comments scraper?

A YouTube comments scraper automatically collects public comments from YouTube videos and converts them into structured records. The data can include comment text, authors, likes, dates, reply counts, and reply threads for research, reporting, moderation, or analysis.

#### How do I scrape comments from a specific YouTube video?

Add the video's full URL or ID to the `videos` input and run the Actor. The extracted comments will appear in the default dataset.

#### Can I scrape comments from YouTube Shorts?

Yes. The Actor accepts YouTube Shorts too — paste a Short's full URL (for example `https://youtube.com/shorts/VIDEOID`) or its video ID into the `videos` input. Comments and replies are collected exactly as they are for regular YouTube videos.

#### Can I scrape comments from multiple YouTube videos at once?

Yes. Add every video URL or ID to the `videos` array. The Actor processes the list in sequence, and `limit` applies to each video separately.

#### Can I collect all comments from a video?

Yes. Leave `limit` empty to continue through the selected feed until the Actor has returned everything YouTube makes available.

#### How do I scrape only recent YouTube comments?

Set `sort` to `newest`, then use `published_after` with a relative value such as `7 days` or an absolute date such as `2026-01-01`.

#### Can this Actor collect YouTube comment replies?

Yes. Set `replies` to `true`. Use `max_replies` to cap replies per comment, or set it to `0` to request all available replies.

#### What is the difference between Top and Newest comments?

`newest` returns YouTube's chronological comment feed. `top` uses YouTube's ranked Top comments feed. Because the order comes from YouTube, Top comments should not be treated as a strict sort by like count alone.

#### How does the YouTube comments scraper API work?

Send the Actor input as JSON to Apify's Run Actor API. For shorter jobs, the synchronous dataset endpoint can return comment records in the same response. For larger jobs, use an asynchronous run and retrieve the default dataset when processing finishes.

#### Do I need the official YouTube Data API?

No official YouTube Data API key is entered in the Actor input.

***

### 🤖 MCP support (Model Context Protocol)

This Actor is compatible with **Apify's hosted MCP server** (`mcp.apify.com`), so AI agents can call it as a tool — **no extra code is needed**. Apify automatically exposes eligible Actors as MCP tools built from their input schema.

#### How it works

Apify's MCP server (`@apify/actors-mcp-server`) discovers this Actor via its name and turns its **input schema** into a single **"run this Actor" tool**. When an agent calls the tool, it runs the Actor and returns the dataset items.

#### Connect it to an MCP client

Add Apify's hosted server to your MCP client (e.g. Claude Desktop, Cursor, or the `mcp` CLI), pointing at this Actor's tool.

**Claude Desktop / `claude_desktop_config.json`:**

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=you/youtube-comments-scraper"
    }
  }
}
```

**Command line:**

```bash
npx @apify/actors-mcp-server --actors you/youtube-comments-scraper
```

Replace `you` with your Apify account username. With the server connected, an agent can ask things like: *"Get the 100 newest comments from this YouTube video"* — the tool runs the Actor with the matching input fields and returns the comments.

#### What the tool exposes

The MCP tool accepts the Actor's input fields as tool arguments (all with sensible defaults except `videos`, which is required):

| Argument | Description |
| --- | --- |
| `videos` | one or more YouTube video IDs or URLs (including Shorts) |
| `limit` | maximum comments |
| `sort` | `newest` or `top` |
| `published_after` | keep comments published after a date/offset |
| `replies` | include replies (`true`/`false`) |
| `max_replies` | cap replies per comment |

#### Requirements

- The Actor must be **accessible** to the account whose token the MCP client uses. If you want third parties to invoke it through a shared MCP server, publish it so it can be run by others (e.g. make it publicly runnable, or grant the calling account access). Private, full-permission, and rented Actors are excluded from the hosted MCP server.
- The MCP client connects with an **Apify token** that has permission to run this Actor.
- An MCP run behaves exactly like a normal run: it writes to the default dataset (one item per comment), charges the PPE events described above, and produces the `OUTPUT` summary.

# Actor input Schema

## `videos` (type: `array`):

One or more YouTube video IDs or full URLs to scrape. At least one required.

## `limit` (type: `integer`):

Target number of comments to collect per video. Comments are paged in batches of 100 via cursor until this many is reached, the chosen 'Sort' feed is exhausted, or the cursor is empty (end of top-level comments). Empty = collect as many as the feed returns. Note YouTube's displayed total counts replies too; the feed returns top-level comments only.

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

Which feed to read. Defaults to Newest. If Newest is requested but unavailable, the request is honoured as empty (no silent fallback to Top).

## `published_after` (type: `string`):

Only keep comments published after this date/time (applied client-side to the top-level comments). Applies to the Newest feed (chronological); it is ignored when sorting by Top. Supports an absolute date (YYYY-MM-DD) or a relative offset like "7 days". A value of 0 (default) keeps all comments.

## `replies` (type: `boolean`):

Expand each comment's replies (nested under each comment).

## `max_replies` (type: `integer`):

Cap replies expanded per comment. 0 (the default) = fetch all replies (no cap). Only applies when 'Include replies' is on; otherwise ignored.

## Actor input object example

```json
{
  "videos": [
    "dQw4w9WgXcQ"
  ],
  "limit": 200,
  "sort": "newest",
  "published_after": "0",
  "replies": false,
  "max_replies": 0
}
```

# Actor output Schema

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

Click to open the dataset of collected comments (one item per comment).

# 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 = {
    "videos": [
        "dQw4w9WgXcQ"
    ],
    "limit": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("poidata/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 = {
    "videos": ["dQw4w9WgXcQ"],
    "limit": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("poidata/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 '{
  "videos": [
    "dQw4w9WgXcQ"
  ],
  "limit": 200
}' |
apify call poidata/youtube-comments-scraper --silent --output-dataset

```

## MCP server setup

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