# YouTube Comments Scraper with Replies (`sebastian-actors/youtube-comments-scraper`) Actor

Extract public YouTube comments and replies with text, likes, authors, badges, pinned and hearted signals, and creator interactions. No YouTube API key or login is required.

- **URL**: https://apify.com/sebastian-actors/youtube-comments-scraper.md
- **Developed by:** [Sebastián S](https://apify.com/sebastian-actors) (community)
- **Categories:** Developer tools, Social media, Videos
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.75 / 1,000 comment scrapeds

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

### What is YouTube Comments Scraper with Replies?

YouTube Comments Scraper with Replies reads publicly available comments from individual YouTube videos, Shorts, and ended live VODs. Provide one or more supported video URLs or raw 11-character video IDs, and the Actor returns flat, structured rows for top-level comments and, optionally, replies. Use the resulting dataset to analyze conversations, creator interactions, links, and engagement without configuring a YouTube API key or signing in to YouTube.

- Accepts up to 1,000 video URLs or IDs per run.
- Uses YouTube's **Top comments** or **Newest first** order.
- Outputs each parent, its replies, then the next parent.
- Extracts text, likes, reply counts, authors, badges, pins, and creator hearts.
- Optionally adds video metadata, links, mentions, and hashtags.
- Deduplicates by `commentId`, including during checkpoint recovery.
- Emits typed status rows for invalid, empty, partial, or failed inputs.

It is HTTP-only and does not crawl channels, read live chat, post comments, translate text, or analyze sentiment.

### What data can it extract or produce?

Each successful comment row can contain:

| Data group         | Exact output fields                                                                                                                                                                                     |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Video              | `videoId`, `videoUrl`, `videoTitle`, `videoChannelId`, `videoChannelName`, `videoDurationSeconds`, `videoPublishedAt`, `videoThumbnailUrl`, `isShort`, `isLive`                                         |
| Thread and order   | `commentId`, `commentUrl`, `threadId`, `parentCommentId`, `kind`, `depth`, `position`, `threadPosition`, `replyPosition`, `sourcePage`, `replyFetchStatus`, `repliesScraped`                            |
| Content and counts | `text`, `links`, `mentions`, `hashtags`, `likeCount`, `likeCountDisplay`, `likeCountPrecision`, `replyCount`, `replyCountDisplay`, `replyCountPrecision`                                                |
| Author             | `authorName`, `authorChannelId`, `authorUrl`, `authorAvatarUrl`, `authorIsVerified`, `authorIsVerifiedArtist`, `authorIsCreator`, `authorIsMember`, `authorBadges`, `memberBadgeName`, `memberBadgeUrl` |
| Signals and timing | `isPinned`, `isCreatorHearted`, `hasCreatorReply`, `isCreatorReply`, `isEdited`, `publishedAt`, `publishedTimeText`, `fetchedAt`                                                                        |
| Traceability       | `schemaVersion`, `recordType`, `status`, `inputIndex`, `input`, `resultKey`, `sort`, `provider`, `extractionAttempt`, `extractionMs`, `warnings`                                                        |

Counts can be `exact`, `approximate`, or `unknown`. Source-dependent values may be `null`. Disabling metadata or author details makes those groups null; disabling text references makes `links`, `mentions`, and `hashtags` null. YouTube may provide only `publishedTimeText`, leaving `publishedAt` null.

### What can you use the data for?

- Analyze audience questions and recurring themes around a video.
- Reconstruct reply threads for community or conversation research.
- Track pinned comments, creator hearts, and creator-authored replies.
- Compare engagement using likes and reported reply counts while respecting count precision.

### How much does it cost?

The Actor uses pay-per-event pricing. The [current Pricing tab](https://apify.com/sebastian-actors/youtube-comments-scraper/pricing) lists:

| Billing event     |      Price | When it is charged                                            |
| ----------------- | ---------: | ------------------------------------------------------------- |
| Actor Start       | `$0.00005` | Once when the Actor starts.                                   |
| `comment-scraped` | `$0.00075` | Once for each successfully stored top-level comment or reply. |

Current formula: **run price = `$0.00005` + (`comment` rows x `$0.00075`)**. The minimal input below allows up to 100 top-level comments and no replies, for a maximum of `$0.07505`; fewer comments cost less. `video-status` rows do not trigger `comment-scraped`, but Actor Start still applies. Check the Pricing tab before a large run because prices can change.

### How to use YouTube Comments Scraper with Replies

#### Quick start

1. Open the Actor in Apify Console and add a video URL or ID.
2. Set limits and enable replies only when needed.
3. Start the run, then open **Output** or the default dataset.

This is the minimal valid input. Omitted settings use the defaults documented in the [Input tab](https://apify.com/sebastian-actors/youtube-comments-scraper/input-schema).

```json
{
    "videoUrls": ["https://www.youtube.com/watch?v=aircAruvnKk"]
}
```

### What input does the Actor accept?

Accepted forms are raw 11-character IDs and individual `youtube.com/watch`, `youtu.be`, `/shorts/`, `/embed/`, `/live/`, `youtube-nocookie.com/embed`, `music.youtube.com/watch`, and mobile watch URLs. Only the video ID is retained. Other YouTube resource types return `UNSUPPORTED_INPUT_TYPE`.

| Field                         | Default                 | Limits and interaction                                                       |
| ----------------------------- | ----------------------- | ---------------------------------------------------------------------------- |
| `videoUrls`                   | Required                | 1-1,000 strings; duplicate video IDs keep only the first input.              |
| `sort`                        | `top`                   | `top` or `newest`; this is YouTube's source order, not a local sort.         |
| `maxTopLevelCommentsPerVideo` | `100`                   | 0-100,000; `0` removes this cap, but hard result caps still apply.           |
| `includeReplies`              | `false`                 | Enables public reply requests; replies are separate billable rows.           |
| `maxRepliesPerThread`         | `20`                    | 0-10,000; used only with replies; `0` requests all available replies.        |
| `maxResultsPerVideo`          | `1000`                  | 1-100,000; hard cap across parents and replies for one video.                |
| `maxTotalResults`             | `10000`                 | 1-1,000,000; hard comment-row cap across the run.                            |
| `includeVideoMetadata`        | `true`                  | Adds a metadata request for available video and channel fields.              |
| `includeAuthorDetails`        | `true`                  | Includes identity, avatar, verification, membership, and badges.             |
| `includeTextReferences`       | `true`                  | Parses links, mentions, and hashtags from YouTube text runs.                 |
| `locale`                      | `en`, `US`              | Session language/country and count parsing; no translation.                  |
| `cleaning`                    | All enabled             | Entity decoding, Unicode NFC, whitespace/control cleanup, and trimming only. |
| `maxVideoConcurrency`         | `4`                     | 1-20 videos processed concurrently.                                          |
| `maxReplyConcurrencyPerVideo` | `3`                     | 1-20 concurrent reply threads per video page.                                |
| `maxRetriesPerRequest`        | `3`                     | 0-5 temporary retries on the same session and proxy identity.                |
| `requestTimeoutSecs`          | `30`                    | 10-120 seconds per YouTube request.                                          |
| `proxyConfiguration`          | Apify residential proxy | Supports Apify Proxy or custom proxy URLs; it can also be disabled.          |
| `debug`                       | `false`                 | Sanitized phases and codes; no content, identities, secrets, or proxy URLs.  |

Replies, zero-as-unlimited settings, and high caps can increase requests, duration, and charge. Hard per-video, run-wide, and spending limits take precedence.

### What output does the Actor produce?

The default dataset contains successful `comment` rows and free `video-status` rows with `empty`, `partial`, or `error` status. This compact, sanitized example uses the same video; see the [Output tab](https://apify.com/sebastian-actors/youtube-comments-scraper/output-schema) for the complete schema.

```json
{
    "recordType": "comment",
    "status": "success",
    "videoId": "aircAruvnKk",
    "commentId": "example-comment-id",
    "threadId": "example-comment-id",
    "parentCommentId": null,
    "kind": "top-level",
    "text": "Clear explanation, thank you!",
    "likeCount": 42,
    "likeCountPrecision": "exact",
    "replyCount": 3,
    "repliesScraped": 0,
    "replyFetchStatus": "not-requested",
    "publishedAt": null,
    "publishedTimeText": "2 years ago"
}
```

Top-level rows have `depth: 0`, a null parent, and their own ID as `threadId`. Replies have `depth: 1` and the parent ID in `threadId` and `parentCommentId`.

Results are stored in the **default dataset**, with `all`, `comments`, `topLevelComments`, `replies`, `creatorInteractions`, `errors`, and `partial` views. Export JSON, JSONL, CSV, Excel, XML, HTML table, or RSS. The default key-value store contains aggregate `OUTPUT` and per-video `VIDEO_SUMMARIES`; `CHECKPOINT` and `EMITTED-IDS-*` are internal recovery state.

### How are errors and partial results handled?

One bad video does not discard other results. If extraction stops after saving comments, they remain and a `video-status` row reports `partial`, `commentsScraped`, `topLevelCommentsScraped`, `repliesScraped`, `completionReason`, `errorCode`, `errorMessage`, `retryable`, and `warnings`. Empty or failed inputs get `empty` or `error` rows.

For empty results, inspect `errors`. For partial threads, check `replyFetchStatus` and `repliesScraped`; a reply failure does not invalidate its parent. Similar text is retained because deduplication uses `commentId`. For network or proxy errors, lower concurrency and retry only when `retryable` is true.

### What are the limits, performance characteristics, and best practices?

Schema ceilings are 1,000 inputs, 100,000 rows per video, and 1,000,000 comment rows per run. They do not guarantee that YouTube will expose that much data. Availability, ordering, metadata, completeness, and duration remain source- and network-dependent; no throughput or completeness guarantee is published.

Start with defaults and a small sample. Replies require more pagination and each stored reply is billable. Lower concurrency when blocks or timeouts increase. Runs use 512 MB by default and allow 512-1,024 MB; more memory does not guarantee more speed.

### How do API, scheduling, webhooks, and integrations work?

The [API tab](https://apify.com/sebastian-actors/youtube-comments-scraper/api) generates REST examples. Node.js and Python `apify-client` packages can call the Actor and read `defaultDatasetId`. API calls need an Apify token, not YouTube credentials.

Save settings as an Apify task and attach a schedule for recurring collection. Use `ACTOR.RUN.SUCCEEDED` or `ACTOR.RUN.FAILED` webhooks, then fetch the run's dataset. Relevant integrations are the Apify node in n8n and the Apify MCP server at `https://mcp.apify.com?tools=sebastian-actors/youtube-comments-scraper`.

### Frequently asked questions

#### Does it need a YouTube API key or login?

No. It creates an anonymous YouTube session. Programmatic runs still require normal Apify authentication.

#### Does it support channels, playlists, live chat, or private content?

No. It accepts individual videos only. Public ended live VOD comments may work; active or upcoming content returns `LIVE_CHAT_NOT_SUPPORTED`. The Actor does not bypass access controls.

#### Will it return every comment and an exact publication timestamp?

Not necessarily. YouTube controls availability and ranking, and limits may stop early. `publishedTimeText` is source-provided; `publishedAt` can be null.

#### How are repeated inputs and comments handled?

Repeated URLs for one video are processed once using the first input index. Comments are deduplicated by `commentId`.

### Is it legal to scrape YouTube comments?

This unofficial Actor is not affiliated with YouTube or Google. It accesses public comments without bypassing controls. Laws, platform terms, privacy duties, and permitted uses vary, so collect only data you have a lawful reason to process, minimize retention, and avoid harmful profiling or redistribution. This is not legal advice.

### Which related Actors should you use?

For spoken content rather than discussion, use [YouTube Transcript & Subtitle Scraper](https://apify.com/sebastian-actors/youtube-transcript-scraper) to extract available transcript text, timestamps, subtitles, and RAG chunks.

### Where can you get support?

Report reproducible problems through the Actor's [Issues tab](https://apify.com/sebastian-actors/youtube-comments-scraper/issues). Include the run ID, sanitized input shape, relevant `errorCode`, and expected behavior; do not post Apify tokens, proxy URLs, cookies, private data, or raw production responses.

# Actor input Schema

## `videoUrls` (type: `array`):

Individual video URLs, Shorts URLs, or raw 11-character video IDs. Channels, playlists, profiles, community posts, and searches return free per-input status rows.

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

Use YouTube's top-comments ranking or newest-first order.

## `maxTopLevelCommentsPerVideo` (type: `integer`):

Maximum unique top-level comments. Use 0 for all available comments.

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

Fetch public replies beneath each top-level comment.

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

Maximum replies per top-level thread. Use 0 for all available replies.

## `maxResultsPerVideo` (type: `integer`):

Hard limit across top-level comments and replies for one video.

## `maxTotalResults` (type: `integer`):

Hard run-wide limit across all comment rows.

## `includeVideoMetadata` (type: `boolean`):

Fetch available title, channel, duration, publication, thumbnail, Shorts, and live metadata.

## `includeAuthorDetails` (type: `boolean`):

Include channel identity, avatar, verification, membership, and badge fields.

## `includeTextReferences` (type: `boolean`):

Extract links, channel mentions, and hashtags from YouTube text runs.

## `locale` (type: `object`):

Language and country sent to the anonymous Innertube session.

## `cleaning` (type: `object`):

Deterministic normalization only. Text is never translated, summarized, censored, or rewritten.

## `maxVideoConcurrency` (type: `integer`):

Number of videos processed concurrently.

## `maxReplyConcurrencyPerVideo` (type: `integer`):

Reply threads fetched concurrently within one top-level page.

## `maxRetriesPerRequest` (type: `integer`):

Temporary request retries on the same session and proxy identity.

## `requestTimeoutSecs` (type: `integer`):

Timeout for each YouTube request.

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

Use Apify Proxy or custom proxy URLs for YouTube requests.

## `debug` (type: `boolean`):

Log sanitized phases and codes without comments, tokens, raw responses, cookies, or proxy URLs.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=aircAruvnKk"
  ],
  "sort": "top",
  "maxTopLevelCommentsPerVideo": 100,
  "includeReplies": false,
  "maxRepliesPerThread": 20,
  "maxResultsPerVideo": 1000,
  "maxTotalResults": 10000,
  "includeVideoMetadata": true,
  "includeAuthorDetails": true,
  "includeTextReferences": true,
  "locale": {
    "language": "en",
    "country": "US"
  },
  "cleaning": {
    "decodeHtmlEntities": true,
    "normalizeUnicode": true,
    "normalizeWhitespace": true,
    "removeInvalidControlCharacters": true,
    "trimWhitespace": true
  },
  "maxVideoConcurrency": 4,
  "maxReplyConcurrencyPerVideo": 3,
  "maxRetriesPerRequest": 3,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "debug": false
}
```

# Actor output Schema

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

No description

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

No description

## `topLevelComments` (type: `string`):

No description

## `replies` (type: `string`):

No description

## `errors` (type: `string`):

No description

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

No description

## `videoSummaries` (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 = {
    "videoUrls": [
        "https://www.youtube.com/watch?v=aircAruvnKk"
    ]
};

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

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

```

## MCP server setup

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