# YouTube Comments Scraper — Comments API & Export | $0.40/1k (`glasswing/youtube-comments-scraper`) Actor

Export YouTube comments and replies without an API key: text, likes, reply count, posting time, pinned, hearted and creator flags. Privacy-safe: no commenter names, handles or profiles. Built for sentiment analysis and market research. $0.40 per 1,000 comments.

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

## Pricing

from $0.40 / 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.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does YouTube Comments Scraper do?

YouTube Comments Scraper exports the **comments and replies of any public YouTube video** as clean JSON, CSV or Excel: comment text, like count, reply count, posting time, and whether the comment is pinned, hearted or written by the creator. It works as a **YouTube comments API alternative**: paste video links or IDs and get the comments back in seconds, with no YouTube API key, no Google account, no quota and no browser.

It is **privacy-safe by design**: rows never contain commenter names, @handles, channel IDs, avatars or profile links, and @mentions inside the text are masked. You get what you need for sentiment analysis and market research, without collecting personal profiles.

Use it to:

- run **sentiment analysis** on the comments under your own videos, a competitor's launch video or a product review;
- do **market research and product feedback mining**: what viewers praise, complain about and ask for, in their own words;
- build **training and evaluation data** for text classifiers, topic models and LLM pipelines from real audience language;
- **monitor new comments** on chosen videos (sort by newest) for community management or brand monitoring.

### Why use YouTube Comments Scraper?

- **No API key, no quota.** YouTube's own Data API needs a Google Cloud project and caps you at a daily quota; this Actor needs neither.
- **Privacy-safe output.** No commenter identity in any row, so the dataset is easier to store, share and process under GDPR-style rules.
- **Creator signals included.** `isPinned`, `isHearted` and `isCreator` show which comments the creator promoted or answered.
- **Replies on demand.** Switch on `includeReplies` to get each thread's replies, linked to their parent with `parentCommentId`.
- **Honest rows.** A video with comments turned off returns one free `not_found` row that says so; the run does not fail and you are not charged for it.
- **Fast and light.** Plain HTTP requests to the same JSON endpoint youtube.com uses; about 20 comments per request. The default run finishes in well under a minute.

### What data can YouTube Comments Scraper extract?

| Field | Type | Description |
|---|---|---|
| `commentId` | string | YouTube's comment id. A reply's id is `<parent id>.<reply id>`. |
| `text` | string | The comment text. @mentions of other users are replaced with `@user`. Empty for the rare sticker-only comment. |
| `likeCount` | integer | Likes on the comment. YouTube rounds large numbers (291K becomes 291000). |
| `replyCount` | integer | Replies under the comment (top-level comments only). |
| `publishedTimeText` | string | Posting time as YouTube shows it, e.g. `3 weeks ago`. |
| `publishedAt` | string | Estimated ISO 8601 time computed from `publishedTimeText` (YouTube shows only relative times, so "6 years ago" is accurate to the year). |
| `isEdited` | boolean | The comment was edited. |
| `isCreator` | boolean | Written by the video's own channel. |
| `isPinned` | boolean | Pinned by the creator. |
| `isHearted` | boolean | Hearted by the creator. |
| `isReply` | boolean | The row is a reply to another comment. |
| `parentCommentId` | string | For replies: the `commentId` of the comment it answers. |
| `position` | integer | 1-based position in the chosen sort order (for replies: within the thread). |
| `videoId` | string | The video's id. |
| `videoUrl` | string | The video's URL. |
| `videoTitle` | string | The video's title. |
| `channelName` | string | The name of the channel that published the video (never a commenter). |
| `videoCommentCount` | integer | The comment total YouTube shows for the video (rounded like on the page). |
| `sortBy` | string | `top` or `newest`, as requested. |
| `inputUrl` | string | The input entry the row came from. |
| `url` | string | Direct link to the comment (`watch?v=<video>&lc=<comment id>`). |

**Not included, on purpose:** commenter display names, @handles, channel IDs, avatar images and profile links.

#### Result status (tri-state output)

| `status` | Meaning | Billed? |
|---|---|---|
| `ok` | One comment or reply. | Yes |
| `not_found` | The video has comments turned off (for example videos made for kids), has no comments yet, is a live stream with chat only, or is unavailable. `error` says which. | No |
| `error` | YouTube could not be read after retries, or the input was not a video link. `error` says why. | No |

### How to scrape YouTube comments with YouTube Comments Scraper

1. Open the Actor in Apify Console and go to the **Input** tab.
2. Paste one or more **YouTube video URLs or IDs** (watch links, youtu.be links, Shorts, live links or bare 11-character IDs).
3. Set **Max comments per video**, choose **Top comments** or **Newest first**, and switch on **Include replies** if you need them.
4. Click **Start**. The default input finishes in about 10 to 30 seconds.
5. Download the comments as JSON, CSV, Excel or HTML, or read them through the API.

Need comments for every video of a channel or a search? List the videos first with [YouTube Scraper](https://apify.com/glasswing/youtube-scraper) and pass their URLs here.

### How much does it cost to scrape YouTube comments?

The Actor uses pay-per-event pricing: you pay for the comments you get, Apify platform usage is included.

| Event | Price |
|---|---|
| Actor start | $0.005 per run |
| Result (`status: ok` row: one comment or reply) | $0.0004 per comment ($0.40 per 1,000) |

Example: 1,000 comments cost about $0.41 ($0.40 plus the $0.005 start fee). Rows with `status` `not_found` or `error` are never billed. The free Apify plan includes enough credit to try the Actor on a several thousand comments. You can cap spending per run with **Maximum results** and in the run's **Max total charge** option.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array of strings | one sample video | Video URLs or IDs, one per line. Channel and playlist links are not accepted. |
| `maxComments` | integer | 50 | Top-level comments per video. Replies come on top of this number. |
| `sortBy` | string | `top` | `top` (YouTube's "Top comments") or `newest` ("Newest first"). |
| `includeReplies` | boolean | false | Also save the replies of each saved comment. |
| `maxRepliesPerComment` | integer | 10 | Replies per comment when `includeReplies` is on. |
| `maxItems` | integer | 1000 | Total rows across all videos; each `ok` row is one billable result. |
| `proxyConfiguration` | object | Apify Proxy (datacenter) | Spreads requests over datacenter IPs so large runs stay clean. Residential proxies are not needed. |

Example input (the prefill):

```json
{
    "startUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
    "maxComments": 20,
    "sortBy": "top",
    "includeReplies": false,
    "maxItems": 20
}
```

Newest comments and replies of two videos:

```json
{
    "startUrls": ["https://youtu.be/plN7JMbadRg", "jNQXAC9IVRw"],
    "maxComments": 100,
    "sortBy": "newest",
    "includeReplies": true,
    "maxRepliesPerComment": 5,
    "maxItems": 1000
}
```

### Output

Two real rows from the default run (text shortened):

```json
[
    {
        "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ&lc=UgzKYksqeQ5gA3t0g0F4AaABAg",
        "status": "ok",
        "scrapedAt": "2026-10-16T12:51:29.783Z",
        "commentId": "UgzKYksqeQ5gA3t0g0F4AaABAg",
        "text": "I Rick rolled my entire French class because we had to study a city in France and make a quiz about it ...",
        "publishedTimeText": "6 years ago",
        "publishedAt": "2020-10-16T00:51:29.782Z",
        "isEdited": true,
        "likeCount": 104000,
        "replyCount": 604,
        "isCreator": false,
        "isPinned": false,
        "isHearted": false,
        "isReply": false,
        "position": 1,
        "videoId": "dQw4w9WgXcQ",
        "videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        "videoTitle": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
        "channelName": "Rick Astley",
        "videoCommentCount": 2400000,
        "sortBy": "top",
        "inputUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    },
    {
        "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ&lc=Ugxzbv_ZeZXNRcfwsSF4AaABAg",
        "status": "ok",
        "commentId": "Ugxzbv_ZeZXNRcfwsSF4AaABAg",
        "text": "Is everyone going to ignore the fact that Rick Astley looks like a twelve year old boy but has a uniquely deep voice?",
        "publishedTimeText": "6 years ago",
        "likeCount": 291000,
        "replyCount": 678,
        "isCreator": false,
        "isPinned": false,
        "isHearted": false,
        "isReply": false,
        "position": 2,
        "videoId": "dQw4w9WgXcQ"
    }
]
```

A video with comments turned off:

```json
{
    "url": "https://www.youtube.com/watch?v=IimtbuqYIE8",
    "status": "not_found",
    "error": "Comments are turned off for this video (free row, not charged).",
    "videoId": "IimtbuqYIE8",
    "videoTitle": "LIVE: NHK WORLD-JAPAN News",
    "channelName": "NHK WORLD-JAPAN"
}
```

### Tips

- **Sentiment over time:** use `sortBy: "newest"` and a fixed `maxComments`, schedule the run daily, and compare the batches.
- **Most influential opinions:** the default `top` order puts the most liked and discussed comments first; `likeCount` and `replyCount` let you weight them.
- **Creator engagement:** filter `isHearted` or `isCreator` to see which comments the creator promoted or answered.
- **Whole channels:** get the video list from [YouTube Scraper](https://apify.com/glasswing/youtube-scraper), then feed the URLs here.

### Limitations

- YouTube publishes only relative times ("3 weeks ago"), so `publishedAt` is an estimate: precise to the minute for fresh comments, to the month or year for old ones.
- Like counts above 1,000 are rounded the way YouTube shows them (1.2K, 291K).
- With **Include replies** on, replies are fetched as soon as their comment is found, so a low **Maximum results** can fill up with replies before later top-level comments arrive. Set `maxItems` to at least `maxComments x (1 + maxRepliesPerComment)` per video when you need both in full.
- Live streams that are on air have live chat, not comments; they return a free `not_found` row. Live chat is not scraped.
- Results reflect what YouTube shows a logged-out visitor in the US at the time of the run; if YouTube changes its page data, rows come back as `error` and the Actor is updated quickly (report it in the **Issues** tab).

### FAQ

#### Do I need a YouTube API key or a Google account?

No. The Actor reads the same public data the youtube.com watch page shows a logged-out visitor. There is no API key, no quota and nothing to sign in to.

#### Does it collect commenter names or profiles?

No. Rows never include display names, @handles, channel IDs, avatars or profile links, and @mentions in the text are masked as `@user`. Only the video's own channel name (`channelName`) is included, because it describes the video, not a commenter.

#### How many comments can I get per video?

As many as YouTube shows, set with **Max comments per video**. YouTube serves about 20 comments per request, so 1,000 comments take about 50 requests and roughly a minute.

#### What happens when comments are turned off?

The video gets one free `not_found` row saying "Comments are turned off for this video". The run still succeeds and other videos are scraped normally.

#### Is it legal to scrape YouTube comments?

Scraping publicly available data is generally legal, but you are responsible for how you use the output. Comments are written by people; this Actor leaves out their identities, but the text itself can still mention personal details. Read the legal notice below and YouTube's terms of service.

#### Can I use this Actor from an AI agent or MCP client?

Yes. Call it through the Apify API or the Apify MCP server with a list of video URLs; every row has a fixed set of fields and a `status`, so an agent can tell "no comments" from "could not read".

#### Why did I get fewer rows than `maxItems`?

`maxItems` is a ceiling. You get fewer rows when the videos have fewer comments than **Max comments per video**, when comments are turned off, or when `maxComments` x the number of videos is below `maxItems`.

#### What if a field is missing?

Optional fields are omitted when YouTube does not show them (for example `replyCount` on replies, or `videoTitle` when YouTube leaves it out). If a field that should always be present is missing, open an issue in the **Issues** tab with the run ID.

### Related Actors

- [YouTube Scraper](https://apify.com/glasswing/youtube-scraper) - list a channel's videos, a playlist or search results with views, likes and comment counts, then scrape their comments here.
- [Google Trends Scraper](https://apify.com/glasswing/google-trends-scraper) - check whether the topic people are discussing is rising or fading.
- [Keyword Suggestions API](https://apify.com/glasswing/keyword-suggestions-scraper) - turn the themes you find in comments into the searches people actually type.
- [Substack Scraper](https://apify.com/glasswing/substack-scraper) - compare a creator's video audience with their newsletter readers.
- [Telegram Channel Scraper](https://apify.com/glasswing/telegram-channel-scraper) - follow the same community's discussion on public Telegram channels.

### Legal and data-protection notice

This Actor extracts only data that YouTube publishes publicly to logged-out visitors; it does not extract private user data such as e-mail addresses, phone numbers, gender or precise location, it deliberately leaves out commenter names, handles, channel IDs, avatars and profile links, and it does not log in or get around access controls. Comment texts are written by people and could still contain personal data. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you are unsure whether your reason is legitimate, consult your lawyers. You are responsible for complying with YouTube's terms of service and applicable law when using the extracted data.

This Actor is an independent tool and is not affiliated with, endorsed by or sponsored by YouTube or Google. All trademarks belong to their respective owners.

# Changelog

This Actor's version history is a separate document: https://apify.com/glasswing/youtube-comments-scraper/changelog.md

# Actor input Schema

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

One per line. Accepted: watch?v= links, youtu.be links, /shorts/, /live/ and /embed/ links, and bare 11-character video IDs. Channel and playlist links are not accepted here (use our YouTube Scraper to list a channel's videos first).

## `maxComments` (type: `integer`):

Top-level comments to save for each video, in the chosen sort order. YouTube serves about 20 per request. Replies (if switched on) come on top of this number.

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

'Top comments' is YouTube's default ranking (most liked and engaged first, pinned comment on top). 'Newest first' is reverse chronological.

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

Also save the replies under each saved comment (each reply is one row with isReply = true and parentCommentId). One extra request per comment that has replies.

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

Only used when 'Include replies' is on. Replies come in YouTube's order, about 10 per request.

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

Stop after this many rows have been saved in total, across all videos. Each saved comment or reply with status `ok` is one billable result. Keep it small for test runs.

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

Apify Proxy (datacenter, the default group) is on by default: YouTube starts refusing one server's requests after a few hundred calls in a row, and spreading them over datacenter IPs keeps large runs clean. Residential proxies are not needed.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "maxComments": 20,
  "sortBy": "top",
  "includeReplies": false,
  "maxRepliesPerComment": 10,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    ],
    "maxComments": 20,
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("glasswing/youtube-comments-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "startUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
    "maxComments": 20,
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("glasswing/youtube-comments-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "maxComments": 20,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call glasswing/youtube-comments-scraper --silent --output-dataset

```

## MCP server setup

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