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

Scrapes comments and replies from YouTube videos and Shorts: text, author and channel, like counts (exact below one million), reply counts, dates, pinned and creator-heart flags. Top or newest first. No login or API key needed.

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

## Pricing

$0.50 / 1,000 comments

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** collects the **comments and replies** of any
[YouTube](https://www.youtube.com) video or Short: the full **comment text,
author handle, channel ID and link, avatar, like count (exact below one million), reply count,
date, and whether the comment is pinned, hearted by the creator or written by
the video's own channel**. Paste video links, choose **Top comments** or
**Newest first**, and optionally add the **replies** under each comment.

Try it with the prefilled video: open the Actor, click **Start**, and the
first 20 comments arrive in a few seconds. It needs **no login, no API key
and no YouTube Data API quota**. Because it runs on the Apify platform, you
also get API access, scheduled runs, integrations (Google Sheets, Make, Zapier,
webhooks), run monitoring and automatic retries through Apify Proxy when
YouTube is slow to answer.

### Why scrape YouTube comments?

- **Audience and product research**: read what viewers say about a product,
  a launch or a review video, in their own words.
- **Sentiment analysis and AI datasets**: export thousands of comments with
  likes and dates as clean JSON or CSV for analysis or model training.
- **Brand and campaign monitoring**: schedule a daily run with **Newest
  first** to catch new comments on your own or your competitors' videos.
- **Creator and influencer analytics**: compare engagement, find the most
  liked comments, and see which ones the creator pinned or hearted.
- **Community management**: collect questions and complaints from the
  replies, not just the top-level comments.

### How to scrape YouTube comments

1. Copy a video link from YouTube, such as
   `https://www.youtube.com/watch?v=dQw4w9WgXcQ`. Shorts links, `youtu.be`
   links and bare video IDs work too.
2. Paste it into **YouTube video links**, one video per line.
3. Set **Max comments per video** and pick **Top comments** or **Newest
   first**.
4. Turn on **Include replies** if you also want the replies to each comment.
5. Click **Start**, then download the results when the run finishes.

### Input

Everything is set on the Input tab. In JSON, the input looks like this:

```json
{
    "startUrls": [
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        "https://youtu.be/kJQP7kiw5Fk",
        "https://www.youtube.com/shorts/ImRy_PiXstI"
    ],
    "maxComments": 500,
    "sortBy": "newest",
    "includeReplies": true,
    "maxRepliesPerComment": 10
}
```

| Field | What it does |
|---|---|
| `startUrls` | Video links, one per line: `watch?v=` links, `youtu.be` links, Shorts, embeds, live links, `m.youtube.com` links or bare 11-character video IDs, with or without `https://`. API callers can also send `{"url": "..."}` objects. |
| `maxComments` | Stops after this many comments per video. Default: 100. Replies don't count toward it. |
| `sortBy` | `top` (Top comments, as YouTube ranks them) or `newest` (Newest first). Default: `top`. |
| `includeReplies` | Also saves the replies to each comment, right after it. Default: off. |
| `maxRepliesPerComment` | When replies are on, stops after this many replies per comment. Default: 10. |
| `proxyConfiguration` | Optional; leave it empty. YouTube answers the Actor directly, and the Actor switches to Apify Proxy by itself if it is ever refused. |

### Output

Each comment, and each reply when you include them, becomes one row. Here is
a real row, the pinned comment on the prefilled video:

```json
{
    "commentId": "Ugzge340dBgB75hWBm54AaABAg",
    "type": "comment",
    "parentCommentId": null,
    "text": "can confirm: he never gave us up",
    "author": "@YouTube",
    "authorChannelId": "UCBR8-60-B28hp2BmDPdntcQ",
    "authorChannelUrl": "https://www.youtube.com/@YouTube",
    "authorAvatarUrl": "https://yt3.ggpht.com/3s6evpqAiDU9tQR4sC2siJippbH2…=s88-c-k-c0x00ffffff-no-rj",
    "isChannelOwner": false,
    "isVerified": true,
    "likeCount": 324682,
    "replyCount": 1000,
    "publishedTimeText": "1 year ago",
    "publishedAt": "2025-10-08T12:47:00+00:00",
    "isEdited": false,
    "isPinned": true,
    "isHeartedByCreator": true,
    "commentUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ&lc=Ugzge340dBgB75hWBm54AaABAg",
    "videoId": "dQw4w9WgXcQ",
    "videoTitle": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
    "videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "videoCommentCount": 2458438,
    "scrapedAt": "2026-10-08T12:47:51.130229+00:00"
}
```

Reply rows have the same fields, with `type` set to `reply`, `parentCommentId`
set to the comment they answer, and a `commentId` that starts with that
comment's ID. The Output tab shows a **Comments** table. You can download the
dataset in various formats such as JSON, HTML, CSV, or Excel.

### Data fields

| Field | Description |
|---|---|
| `commentId` | YouTube's ID of the comment or reply. |
| `type` | `comment` for a top-level comment, `reply` for a reply. |
| `parentCommentId` | For replies, the ID of the comment they answer; `null` for comments. |
| `text` | The full comment text, with line breaks and emoji. |
| `author` | The commenter's @handle, which is the name YouTube shows on comments. |
| `authorChannelId` | The commenter's channel ID (`UC…`), stable even if the handle changes. |
| `authorChannelUrl` | Link to the commenter's channel. |
| `authorAvatarUrl` | The commenter's profile picture. |
| `isChannelOwner` | `true` when the comment was written by the video's own channel. |
| `isVerified` | `true` when the commenter's channel is verified. |
| `likeCount` | Number of likes, exact below one million (YouTube rounds larger counts, for example to 4,800,000). |
| `replyCount` | Number of replies, as YouTube counts them. Always 0 on replies. |
| `publishedTimeText` | The age YouTube shows, such as `3 weeks ago`. |
| `publishedAt` | The approximate date and time in UTC (ISO 8601): the scrape time minus that age. YouTube rounds ages down, so the real date can be up to one unit earlier, for example up to a year earlier for `5 years ago`. |
| `isEdited` | `true` when the comment was edited. |
| `isPinned` | `true` for the comment the creator pinned. |
| `isHeartedByCreator` | `true` when the creator gave the comment a heart. |
| `commentUrl` | Link that opens the video with this comment highlighted. |
| `videoId`, `videoTitle`, `videoUrl` | The video the comment belongs to. |
| `videoCommentCount` | The video's comment count as YouTube shows it under the video, replies included. |
| `scrapedAt` | When the row was saved. |

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

YouTube Comments Scraper uses **pay-per-event** pricing: you pay only for the
rows you get, one comment or one reply each. See the **Pricing** tab for the
exact price per 1,000 comments. Apify's free plan includes monthly credit you
can use to try it.

Videos that return nothing (comments turned off, private, removed or invalid
links) are never saved as rows, so you are not charged for them. If you set a
maximum cost for a run, the Actor stops as soon as it is reached.

### Tips for scraping YouTube comments

- **To get every comment, use Newest first** with a large **Max comments per
  video** (for example 100000). YouTube's Top comments order can stop after
  about 1,000 comments on some videos, while Newest first goes all the way
  back.
- **For monitoring**, schedule a daily run with **Newest first** and a small
  limit, and keep only comments newer than your last run by `publishedAt`.
- **Replies multiply the row count.** A popular comment can have hundreds of
  replies, so keep **Max replies per comment** small unless you need them all.
- **Speed**: roughly 1,000 comments per video in 15 to 20 seconds, and three
  videos are read at the same time.
- Each comment is saved only once per video, even when YouTube lists it twice.
- If the run's time limit is close, the Actor stops paging and finishes
  cleanly with everything collected so far.

### FAQ, disclaimers and support

**Which videos work?** Any public video, Short or past live stream with
comments turned on, including **age-restricted videos**. Videos whose comments
are turned off (for example videos made for kids), live streams that only have
a live chat, and private or removed videos have no comments to give.

**What happens to links that return nothing?** They are not saved as rows,
so you are not charged for them. Each one is listed with its reason (for
example `YouTube says: Comments are turned off.`) in the `FAILED_INPUTS`
record of the run's key-value store, and the run's status message gives the
counts. A run fails only when every video failed because YouTube could not be
reached.

**Why does a comment have fewer replies than its reply count?** The count
comes from YouTube and can include replies it no longer shows, such as
deleted or held-for-review replies.

**Why are like counts above a million rounded?** YouTube itself only gives
those as rounded numbers such as 4.8 million. Below a million, the counts are
exact.

**Is it legal to scrape YouTube comments?** This Actor collects only comments
that are publicly visible on YouTube to anyone without logging in. Comments
contain personal data such as usernames, profile pictures and whatever people
wrote, so you are responsible for making sure your use complies with
YouTube's Terms of Service and with data protection laws such as the GDPR.
Collect only what you need, and if in doubt, ask a lawyer.

**Found a problem or need a custom solution?** Open an issue on the
**Issues** tab and we will look into it. Custom scrapers and data feeds are
available on request.

# Actor input Schema

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

One video per line. Watch links, youtu.be links, Shorts, embeds, live links, m.youtube.com links and bare 11-character video ids all work, with or without https://. Links that are not videos (channels, playlists) are listed in the FAILED_INPUTS record.

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

Stops after this many comments for each video. Replies are not counted here; they have their own limit below. To get every comment of a video, set a large number such as 100000.

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

The order YouTube lists the comments in, as in the sort menu above a video's comments. A pinned comment comes first in both orders.

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

Also saves the replies to each comment, right after the comment, marked with type "reply" and the id of the comment they answer. Each reply is one more row.

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

When replies are included, stops after this many replies to each comment, oldest first, as YouTube lists them.

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

Leave this empty: YouTube answers the Actor directly, and if it ever refuses, the Actor retries through Apify's proxies on its own. Choose a proxy here only to send every request through it.

## Actor input object example

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

# Actor output Schema

## `dataset` (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
};

// Run the Actor and wait for it to finish
const run = await client.actor("mina_safwat/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,
}

# Run the Actor and wait for it to finish
run = client.actor("mina_safwat/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
}' |
apify call mina_safwat/youtube-comments-scraper --silent --output-dataset

```

## MCP server setup

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