# YouTube Comments Scraper With Reply Thread Expansion (`scrapio/youtube-comments-scraper`) Actor

YouTube Comments Scraper extracts YouTube comments with reply thread expansion, including comment text, authors, timestamps, likes, reply counts, nested replies, and video details. Ideal for sentiment analysis, audience research, engagement tracking, and content insights.

- **URL**: https://apify.com/scrapio/youtube-comments-scraper.md
- **Developed by:** [Scrapio](https://apify.com/scrapio) (community)
- **Categories:** Lead generation, Social media, Videos
- **Stats:** 3 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Scraper — Extract Comments, Reply Threads and Commenter Data

YouTube Comments Scraper With Reply Thread Expansion pulls top-level comments, fully expanded reply threads, and commenter data (handle, avatar, verified/creator badges, like counts) from any public YouTube video — returned as clean, typed JSON. Unlike scraping frameworks that return raw HTML, it returns structured records ready for your database, spreadsheet, or LLM pipeline without any parsing. What sets it apart from a standard comment exporter is that it follows each parent comment's own "more replies" continuation token, recovering the full thread instead of the 2-3 replies YouTube previews inline. This guide covers every input and output field and how teams deploy it for moderation, sentiment analysis, and dataset building.

### 🧭 What Does YouTube Comments Scraper With Reply Thread Expansion Do?

This Actor takes one or more YouTube video URLs (or bare video IDs) and scrapes every top-level comment plus, optionally, every reply hiding behind "View N more replies." No YouTube account or login is required — the Actor fetches public video pages and the same `/youtubei/v1/next` endpoint YouTube's own web client uses, so it only ever sees what an anonymous visitor can see.

- Scrapes top-level comments and fully expanded reply threads in one run
- Follows each parent comment's own reply-continuation token rather than relying on YouTube's inline preview (which now ships 0 real reply objects, only a "load more" token)
- Returns commenter data on every row: handle, avatar URL, channel-owner flag, verified badge, like count, creator-heart flag
- Filters rows by keyword (include and exclude) across the entire thread — comments and replies alike
- Sorts top-level comments by "top" (most liked) or "newest"
- Bulk-processes multiple videos in a single run
- Auto-escalates through no-proxy → datacenter → residential proxy tiers on a block

### ⚡ Features & Capabilities

The Actor's feature set splits into thread-expansion mechanics, keyword filtering, and honest field labeling — each covered below.

#### Core features

- **Full reply-thread pagination** — follows every parent comment's own `continuationCommand` token via the `/youtubei/v1/next` endpoint until YouTube stops returning new replies, `maxRepliesPerComment` is hit, or a 40-page-per-comment safety valve is reached (`MAX_REPLY_PAGES_PER_PARENT = 40` in source), so the run always terminates
- **Keyword include/exclude filtering** — `includeKeywords` / `excludeKeywords` apply a case-insensitive substring match to every row's `comment` text, comments and replies alike, before the row is pushed (and billed)
- **Honest `isPinned` field** — pinned status is resolved independently from `renderingPriority == 'RENDERING_PRIORITY_PINNED_COMMENT'` on the comment thread, and no longer forces `authorIsChannelOwner: true` just because a comment is pinned (a creator can pin any user's comment)
- **Correct `type` / `isChild` labeling** — replies are labeled `"reply"` with `isChild: true`; parents are `"comment"` with `isChild: false`
- **Per-run child dataset mirror** — every `isChild: true` row is also written to a separate dataset named `replies-<runId>`, so replies can be exported independently from top-level comments
- **20 fields per row**, including `cid`, `voteCount`, `replyCount`, `hasCreatorHeart`, `replyToCid`, `commentUrl`, and an absolute `scrapedAt` UTC timestamp — see the full Output Format section below
- Accepts full video URLs, `youtu.be` short links, `/embed/` URLs, or bare 11-character video IDs
- Backward-compatible with the base YouTube Comments Scraper's input keys (`startUrls`, `maxComments`, `sortOrder`, hidden `language`/`region`) so existing input JSON keeps working

#### YouTube Comments Scraper With Reply Thread Expansion within the Scrapio data stack

This Actor covers comments and reply threads. For channel-level subscriber/view/video growth tracking, use **YouTube Channel Finder With Subscriber Counts**. For retention heatmaps, chapter markers, and derived engagement-rate/view-velocity metrics on top of threaded comments, use **YouTube Scraper With Comment & Engagement Analytics**. For transcripts paired with view/like analytics, use **YouTube Transcript Scraper With View & Like Analytics**.

### Why do developers and data teams scrape YouTube?

YouTube comment sections are one of the largest public repositories of unstructured audience reaction on the internet — the audiences below are the ones that actually pull this kind of data at volume.

#### 🏢 Brand, community, and moderation teams

Community managers pull `comment`, `author`, `voteCount`, and `replyCount` to find the highest-engagement threads under a video and audit what's actually being said in the replies — not just the top-level comment a casual viewer sees. `includeKeywords` lets a team pull only rows mentioning a product or competitor name across an entire thread, including replies that never surface in YouTube's own UI without manually clicking through. `isPinned` and `authorIsChannelOwner` (now reported independently, not conflated) let moderation teams audit exactly which comments a creator chose to pin and which replies came from the creator versus fans.

#### 📊 AI training data and RAG indexing

The `comment` field is the high-information text field here — full comment and reply bodies, already separated from HTML markup and YouTube's UI chrome, requiring no cleanup before embedding. For RAG, indexing `comment` alongside `videoId`, `title`, and `publishedTimeText` lets a retrieval system answer "what are people saying about video X" with attributable, sourced text. For training data, the consistent 20-field schema across both comments and replies (same keys, `type` and `isChild` distinguishing them) means a single parser handles the entire dataset without per-row branching.

#### 📱 Competitive and market intelligence

Tracking `voteCount` and `replyCount` on comments mentioning a competitor's product across multiple videos surfaces which claims and complaints are actually resonating with an audience, not just which video got the most views. Running the Actor against a competitor's product-review or launch videos with `includeKeywords` set to a product name turns scattered public reaction into a structured feed a marketing or product team can track over time.

#### 🔬 Research and academic use

Researchers studying online discourse, misinformation spread, or community dynamics use this Actor to pull complete conversation threads — including the reply layer most comment scrapers never reach — rather than the truncated top-level sample YouTube's page shows by default. This Actor only returns publicly accessible comments; it does not access private, age-restricted, or members-only content.

#### 🎥 Product and SaaS development

Teams building sentiment dashboards, creator-analytics tools, or moderation-assist products use the Actor's JSON output as the raw feed behind their own enrichment layer, appending sentiment scores or spam classifiers on top of the `comment`, `voteCount`, and `replyCount` fields already provided.

### 🍚 Input Parameters

No input parameter is required — the Actor uses documented defaults for everything except `videoUrls`, which must be non-empty for a run to do anything.

| Parameter | Required | Type | Description | Example Value |
| --- | --- | --- | --- | --- |
| `videoUrls` | No | array | YouTube video URLs or bare 11-character IDs to scrape. Also accepts the base actor's `startUrls` key. | `["https://www.youtube.com/watch?v=KrLj6nc516A"]` |
| `maxTopLevelComments` | No | integer | Caps top-level (parent) comments scraped per video; replies are not counted against this. `0` = no limit. Default `50`. Also accepts `maxComments`. | `50` |
| `commentSortOrder` | No | string (enum: `top`, `newest`) | Order top-level comments are fetched in — `top` (most liked, YouTube default) or `newest`. Also accepts `sortOrder`. | `"top"` |
| `fetchAllReplies` | No | boolean | When `true` (default), follows each parent's own reply-continuation token to recover the full thread. When `false`, only inline-preview replies are kept. | `true` |
| `maxRepliesPerComment` | No | integer | Caps replies kept per parent when `fetchAllReplies` is on, counted after keyword filters. `0` = unlimited, up to a 40-page safety valve per comment. Default `50`. | `100` |
| `includeKeywords` | No | array | Case-insensitive substring match; only rows (comments and replies) containing at least one keyword are kept. Empty = keep everything. Default `[]`. | `["giveaway"]` |
| `excludeKeywords` | No | array | Case-insensitive substring match; rows containing any keyword are dropped. Same full-thread scope as `includeKeywords`. Default `[]`. | `["spam"]` |
| `commentLanguage` | No | string | Locale for YouTube's response; affects relative-date text like "2 years ago." Default `en-GB`. Also accepts hidden `language` key. | `"en-US"` |
| `commentRegion` | No | string | Country code used for the request. Default `US`. Also accepts hidden `region` key. | `"US"` |
| `proxyConfiguration` | No | object | Apify Proxy settings. No proxy by default; the Actor auto-escalates to datacenter then residential on a 403/429 block. | `{"useApifyProxy": false}` |

**JSON input example:**

```json
{
  "videoUrls": ["https://www.youtube.com/watch?v=KrLj6nc516A", "dQw4w9WgXcQ"],
  "maxTopLevelComments": 50,
  "commentSortOrder": "top",
  "fetchAllReplies": true,
  "maxRepliesPerComment": 100,
  "includeKeywords": [],
  "excludeKeywords": ["spam"],
  "commentLanguage": "en-GB",
  "commentRegion": "US",
  "proxyConfiguration": { "useApifyProxy": false }
}
```

#### Supported URL types and input formats

The Actor's `extract_video_id()` parser accepts four input shapes in `videoUrls`, resolved in this order:

- **Bare video ID** — an 11-character alphanumeric string, e.g. `"dQw4w9WgXcQ"`
- **Standard watch URL** — `"https://www.youtube.com/watch?v=KrLj6nc516A"`
- **Short link** — `"https://youtu.be/KrLj6nc516A"`
- **Embed URL** — `"https://www.youtube.com/embed/KrLj6nc516A"`

Mixed formats can be combined in the same `videoUrls` array. Any entry that fails to resolve to a valid video ID is skipped with a logged warning, and the rest of the run continues.

### 📦 Output Format

Every scraped row is a typed JSON object with a stable 20-key schema shared by both comments and replies — `type` and `isChild` are what distinguish them, not a different field set. Output is delivered through the Actor's Apify dataset, exportable in the formats Apify datasets support (JSON, CSV, Excel, XML, HTML table, RSS).

#### Output for Comments (top-level)

```json
{
  "cid": "Ugzxs4_5UJwAI1xrNF14AaABAg",
  "type": "comment",
  "isChild": false,
  "isPinned": true,
  "publishedTimeText": "2 years ago",
  "comment": "This trick actually works, tried it on my own channel last week!",
  "author": "@TechReviewsDaily",
  "avatar": "https://yt3.ggpht.com/ytc/AIdro_kJ3f8s9-example-avatar=s88-c-k-c0x00ffffff-no-rj",
  "authorIsChannelOwner": true,
  "isVerified": true,
  "voteCount": 18900,
  "hasCreatorHeart": true,
  "replyCount": 764,
  "replyToCid": null,
  "videoId": "KrLj6nc516A",
  "pageUrl": "https://www.youtube.com/watch?v=KrLj6nc516A",
  "commentUrl": "https://www.youtube.com/watch?v=KrLj6nc516A&lc=Ugzxs4_5UJwAI1xrNF14AaABAg",
  "title": "How I Doubled My Channel's Watch Time in 30 Days",
  "commentsCount": 15500,
  "scrapedAt": "2026-07-25T12:00:00Z"
}
```

#### Output for Reply Threads

Reply rows share the identical 20-key schema — the only structural difference is `isChild: true`, `type: "reply"`, and a populated `replyToCid` linking back to the parent comment's `cid`:

```json
{
  "cid": "Ugzxs4_5UJwAI1xrNF14AaABAg.9uj377Q6pSj9uj3Bb6-u_Y",
  "type": "reply",
  "isChild": true,
  "isPinned": false,
  "publishedTimeText": "2 years ago",
  "comment": "Same here, subscriber count jumped after I tried this",
  "author": "@GrowthWithJen",
  "avatar": "https://yt3.ggpht.com/ytc/AIdro-example-avatar-2=s88-c-k-c0x00ffffff-no-rj",
  "authorIsChannelOwner": false,
  "isVerified": false,
  "voteCount": 2100,
  "hasCreatorHeart": false,
  "replyCount": 0,
  "replyToCid": "Ugzxs4_5UJwAI1xrNF14AaABAg",
  "videoId": "KrLj6nc516A",
  "pageUrl": "https://www.youtube.com/watch?v=KrLj6nc516A",
  "commentUrl": "https://www.youtube.com/watch?v=KrLj6nc516A&lc=Ugzxs4_5UJwAI1xrNF14AaABAg.9uj377Q6pSj9uj3Bb6-u_Y",
  "title": "How I Doubled My Channel's Watch Time in 30 Days",
  "commentsCount": 15500,
  "scrapedAt": "2026-07-25T12:00:00Z"
}
```

Reply rows are also mirrored into a separate per-run dataset named `replies-<runId>`, so a downstream job can pull just the reply layer without filtering the main dataset by `isChild`.

#### Schema stability and export options

Field names are fixed by the Actor's row-building functions, not by whatever YouTube's front end happens to render that day — so the 20-key shape stays stable even as YouTube's internal page structure changes; the Actor already carries fallback parsing paths for two different YouTube comment renderer shapes (`commentEntityPayload` and legacy `commentThreadRenderer`) to absorb that kind of front-end drift without changing output keys. Every dataset row corresponds to exactly one billed `row_result` event — rows dropped by `includeKeywords`/`excludeKeywords` are filtered before the push, so filtered-out comments are never charged. Results export from the Apify dataset in JSON, CSV, Excel, XML, HTML table, or RSS, and are also readable programmatically via the Apify API or client SDKs.

### 💡 YouTube Comments Scraper With Reply Thread Expansion Strategy Guide

#### 🎯 Strategy 1: Real-time enrichment pipeline

Trigger a run whenever a new video mention needs auditing — a brand-monitoring alert, a support ticket referencing a video, or a creator publishing a new upload. Run the Actor with that single `videoUrls` entry, then read the pushed rows' `comment`, `author`, `voteCount`, and `replyToCid` fields to enrich a CRM record or support ticket with "what's actually being said in the replies," not just the top comment. Because `commentUrl` is a direct deep link to the comment, the enrichment record can link straight back to the source for a human reviewer.

#### 🎯 Strategy 2: Scheduled monitoring and alerting

Schedule recurring runs (via Apify's Schedule feature on the platform) against a fixed set of `videoUrls` — a channel's recent uploads, or videos already flagged for moderation. Diff each run's rows against the previous run on `cid`, `voteCount`, and `replyCount`: new `cid` values are new comments/replies since the last run, and a jump in `voteCount` on an existing `cid` signals a comment gaining traction. Pair with `excludeKeywords` to suppress known spam patterns before they ever reach the alerting layer.

#### 🎯 Strategy 3: Bulk dataset build

Pass a large `videoUrls` array (or the base actor's `startUrls` key) in one run to build a research or training dataset across many videos; the Actor loops through the list sequentially within a single run, so for very large batches, split the URL list across multiple parallel runs launched via the Apify API rather than one oversized run. Aggregate the resulting datasets to CSV or a database using the Actor's own field schema — no reshaping needed since comments and replies share one 20-key shape.

#### Strategy comparison at a glance

| Strategy | Best for | Run pattern | Output format |
| --- | --- | --- | --- |
| Real-time enrichment | Single-video, on-demand lookups | One run per trigger event | JSON via dataset/API |
| Scheduled monitoring | Ongoing tracking of a fixed video/channel set | Recurring scheduled runs, diffed on `cid`/`voteCount` | JSON, diffed programmatically |
| Bulk dataset build | Large-scale research or training corpora | One run per URL batch, or multiple parallel runs | CSV/Excel export from dataset |

### 🌴 Related YouTube Scrapers & Tools

| Scraper Name | What it extracts |
| --- | --- |
| YouTube Channel Finder With Subscriber Counts | Per-channel subscriber, view, and video-count growth tracked across re-runs |
| YouTube Scraper With Comment & Engagement Analytics | Video metadata, retention heatmap, chapter markers, and threaded comments with derived engagement rate and view velocity |
| YouTube Transcript Scraper With View & Like Analytics | Video transcripts paired with view/like metadata and locally computed engagement analytics |
| Instagram Comments Scraper With Engagement Analytics | Instagram post/reel comments with engagement metrics |
| Facebook Comments Scraper | Comments scraped from Facebook posts |
| Facebook Group Comments & Replies Scraper | Comments and replies from Facebook Group posts |
| Reddit Comment Scraper (Sentiment & Lead Scoring) | Reddit comments with sentiment and lead-scoring fields |

### How to integrate YouTube Comments Scraper With Reply Thread Expansion with your stack

YouTube Comments Scraper With Reply Thread Expansion works with any language or tool that can call the Apify API — the examples below use Apify's official client SDKs, the genuine way this Actor is invoked programmatically.

#### Python

```python
from apify_client import ApifyClient
import csv

client = ApifyClient("<YOUR_APIFY_API_TOKEN>")

video_urls = [
    "https://www.youtube.com/watch?v=KrLj6nc516A",
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
]

run_input = {
    "videoUrls": video_urls,
    "maxTopLevelComments": 50,
    "fetchAllReplies": True,
    "maxRepliesPerComment": 100,
    "excludeKeywords": ["spam"],
}

run = client.actor("Scrapio/youtube-comments-scraper-with-reply-thread-expansion").call(run_input=run_input)

rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())

with open("youtube_comments.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=rows[0].keys())
    writer.writeheader()
    writer.writerows(rows)

print(f"Saved {len(rows)} comment/reply rows to youtube_comments.csv")
```

#### Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_API_TOKEN>' });

const run = await client.actor('Scrapio/youtube-comments-scraper-with-reply-thread-expansion').call({
    videoUrls: ['https://www.youtube.com/watch?v=KrLj6nc516A'],
    maxTopLevelComments: 50,
    fetchAllReplies: true,
    maxRepliesPerComment: 100,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();

console.log(`Fetched ${items.length} rows`);
console.log(items[0]);
```

#### Async and scheduled pipelines

The Actor is invoked as a standard Apify Actor run — there is no separate webhook server inside the Actor itself. For fire-and-forget large jobs, start the run via `client.actor(...).start()` instead of `.call()`, poll the run status or dataset via the Apify API, or configure an Apify webhook on the run-succeeded event to notify your own endpoint. Recurring jobs use the Apify platform's Schedule feature to trigger runs on a cron-style interval against a fixed `videoUrls` list.

### 🎯 Who Needs YouTube Comments Scraper With Reply Thread Expansion? (Use Cases & Industries)

#### 🏢 Brand, community, and moderation teams

A community manager pulls every reply under a flagged top-level comment (`replyToCid` chains back to the parent `cid`) to see whether a complaint escalated in the replies before deciding whether to respond publicly or pin a clarifying comment.

#### 📊 AI/ML teams building RAG and training data

Teams indexing `comment` text alongside `videoId` and `title` into a vector store get a sourced, attributable feed of audience reaction for retrieval-augmented answers about "what viewers think of video X," without re-scraping HTML for each new video.

#### 📱 Competitive intelligence and marketing teams

Marketing teams run the Actor against competitor product-launch videos with `includeKeywords` set to their own or a competitor's product name, tracking `voteCount` on those specific mentions over multiple runs to see which claims are actually landing with viewers.

#### 🔬 Researchers

Academic and social researchers use the full reply-thread expansion to study complete public conversation structures — not the truncated top-level sample most comment scrapers return — while only ever touching publicly accessible comments.

#### 🎥 Product and SaaS builders

Builders of sentiment dashboards and moderation-assist tools use the Actor's stable 20-field JSON as the ingest layer behind their own scoring or classification models, without writing YouTube-specific HTML parsing themselves.

### Is it legal to scrape YouTube?

Scraping publicly accessible web pages is generally lawful in the United States — courts have repeatedly held that accessing data a website makes available to any visitor without a login does not violate the Computer Fraud and Abuse Act (see *hiQ Labs, Inc. v. LinkedIn Corp.*, 9th Cir. 2019, reaffirmed on remand 2022). Separately, scraping in a way that breaches a platform's Terms of Service can expose the scraper to a civil contract claim from that platform — a different and independent question from criminal liability. Because this Actor returns commenter handles, avatar images, and comment text tied to identifiable YouTube accounts, that output is personal data under frameworks like GDPR and CCPA: storing, processing, or publishing it carries data-protection obligations that sit with whoever runs the Actor, not with the Actor itself. YouTube Comments Scraper With Reply Thread Expansion returns only publicly accessible data. What you do with that data is your responsibility — consult legal counsel for commercial applications involving personal data.

### ❓ Frequently asked questions

#### Does YouTube Comments Scraper With Reply Thread Expansion work without a YouTube account?

Yes. The Actor fetches public video pages and the same `/youtubei/v1/next` endpoint an anonymous browser uses — no YouTube login or API key is required. It only returns data visible to a logged-out visitor, so private, unlisted-without-link, or age-restricted videos are out of scope.

#### How does it handle YouTube's anti-scraping measures?

On a `403`/`429` response, the Actor automatically escalates from no proxy to a datacenter proxy, then to a residential proxy, retrying up to `MAX_RETRIES = 3` times with a backoff delay between attempts. Requests also rotate a realistic Chrome user-agent string matched to the detected client version.

#### Can I run it at scale without getting blocked?

Multiple videos in `videoUrls` are processed sequentially within one run, with proxy escalation handling individual blocks as they occur. No fixed rate limit or concurrency cap is published for this Actor; for very large batches, running multiple parallel Actor runs (each with its own `videoUrls` subset) via the Apify API scales better than one very large run.

#### How fresh is the data it returns?

Fully live — every run fetches the video page and comment continuations directly from YouTube at request time. Nothing is cached or served from a prior run; re-running against the same video returns whatever comments and replies exist at that moment.

#### Does scraping YouTube comments violate YouTube's Terms of Service?

Scraping public pages does not, by itself, violate US anti-hacking law (see the *hiQ v. LinkedIn* citation above), but YouTube's own Terms of Service restrict automated access — breaching those terms is a potential civil contract issue between the scraper and YouTube, not a criminal one. Users are responsible for evaluating that risk for their own use case.

#### Which fields work best for AI training and RAG indexing?

`comment` is the primary high-information text field for both RAG retrieval and training corpora. For RAG, pair it with `videoId`, `title`, and `publishedTimeText` so retrieved passages are attributable to a specific video and time. For training data, `type` and `isChild` give a consistent, non-null way to separate top-level comments from replies across the entire dataset without per-row branching — every field returns as a typed primitive (string, integer, or boolean), requiring no additional normalization.

#### Does this Actor return personal data, and who is responsible for handling it?

Yes — `author` (handle), `avatar` (profile image URL), and `comment` text tied to an identifiable account are personal data under regimes like GDPR and CCPA. The Actor only surfaces what YouTube already displays publicly; the lawful basis for storing, processing, or further using that data rests with whoever operates the Actor, not with the Actor itself.

#### Does it work with Claude, ChatGPT, and other AI agent tools?

There is no dedicated MCP server for this Actor. It is callable as a standard Apify Actor run through the Apify API by any agent framework capable of making an HTTP request — every response is typed JSON, so no HTML parsing is needed before passing results into an LLM's context window.

#### What happens if I set maxRepliesPerComment to 0?

`0` means no cap on replies kept per parent comment — the Actor keeps following that comment's reply-continuation token until YouTube stops returning new replies or a 40-page-per-comment safety valve is reached (`MAX_REPLY_PAGES_PER_PARENT = 40`), guaranteeing the run still terminates on an exceptionally large thread.

#### Will my existing base-actor input JSON still work with this Actor?

Yes. `startUrls`, `maxComments`, `sortOrder`, and the hidden `language`/`region` keys from the base YouTube Comments Scraper are all still accepted as fallbacks — the new field names (`videoUrls`, `maxTopLevelComments`, `commentSortOrder`, `commentLanguage`, `commentRegion`) take priority if both are present, but old input JSON does not need to be rewritten.

### ℹ️ Disclaimer

YouTube Comments Scraper With Reply Thread Expansion extracts only publicly available data from YouTube. This tool is intended for lawful use cases only. Users are responsible for complying with YouTube's terms of service and applicable data protection laws in their jurisdiction.

# Actor input Schema

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

📋 The YouTube videos to scrape comments + full reply threads from. Full URLs (https://www.youtube.com/watch?v=VIDEO\_ID or https://youtu.be/VIDEO\_ID) or bare 11-character video IDs both work. Add multiple entries to process several videos in one run. (Also accepts the base actor's `startUrls` key.)

## `maxTopLevelComments` (type: `integer`):

🔢 Caps the number of TOP-LEVEL (parent) comments scraped per video — replies are NOT counted against this limit, they are capped separately by 'Maximum Replies per Comment' below. Use 0 for no limit. Example: maxTopLevelComments=10 + maxRepliesPerComment=20 → up to 10 parent comments, each with up to 20 of its replies. Default is 50. (Also accepts the base actor's `maxComments` key — note: in the base, maxComments counted comments AND inline replies together; here it only counts parents.)

## `commentSortOrder` (type: `string`):

⬆️ How top-level comments are ordered. • top — most liked/relevant first (YouTube's default). • newest — most recently posted first. (Also accepts the base actor's `sortOrder` key.)

## `fetchAllReplies` (type: `boolean`):

🧵 When ON (default), follows EACH parent comment's own 'more replies' continuation token to fetch every reply YouTube is hiding behind the 'View N more replies' button — not just the 2-3 shown inline. When OFF, behaves like a normal comments scraper (inline-preview replies only, matching the base actor).

## `maxRepliesPerComment` (type: `integer`):

🧢 Caps how many replies are KEPT per parent comment when 'Expand Full Reply Threads' is ON (counted after Include/Exclude Keyword filters are applied — a strict filter may page deeper into the thread to find that many matches). Use 0 for no limit (up to a 40-page safety valve per comment). Default is 50.

## `includeKeywords` (type: `array`):

✅ Only keep rows (comments AND replies) whose text contains at least one of these keywords (case-insensitive substring match). Applied across the FULL thread — a matching reply is kept even if its parent comment doesn't match. Leave empty to keep everything.

## `excludeKeywords` (type: `array`):

⛔ Drop any row (comment OR reply) whose text contains one of these keywords (case-insensitive substring match). Applied across the FULL thread, same scope as Include Keywords. Leave empty to disable.

## `commentLanguage` (type: `string`):

Locale for YouTube's response (affects relative-date text like '2 years ago'). Default en-GB. (Also accepts the base actor's hidden `language` key.)

## `commentRegion` (type: `string`):

Country code used for the request. Default US. (Also accepts the base actor's hidden `region` key.)

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

Configure Apify Proxy. By default no proxy is used; the actor auto-escalates no-proxy → datacenter → residential on a block (403/429).

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.youtube.com/watch?v=KrLj6nc516A"
  ],
  "maxTopLevelComments": 50,
  "commentSortOrder": "top",
  "fetchAllReplies": true,
  "maxRepliesPerComment": 50,
  "includeKeywords": [],
  "excludeKeywords": [],
  "commentLanguage": "en-GB",
  "commentRegion": "US",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

All scraped items in the Actor's default dataset.

# 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=KrLj6nc516A"
    ],
    "maxTopLevelComments": 50,
    "commentSortOrder": "top",
    "commentLanguage": "en-GB",
    "commentRegion": "US",
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapio/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=KrLj6nc516A"],
    "maxTopLevelComments": 50,
    "commentSortOrder": "top",
    "commentLanguage": "en-GB",
    "commentRegion": "US",
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapio/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=KrLj6nc516A"
  ],
  "maxTopLevelComments": 50,
  "commentSortOrder": "top",
  "commentLanguage": "en-GB",
  "commentRegion": "US",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call scrapio/youtube-comments-scraper --silent --output-dataset

```

## MCP server setup

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