# YouTube Comments Scraper — Text, Likes & Replies, No Names (`northbell/youtube-comments-scraper`) Actor

Comments of any public YouTube video: text, likes, reply counts, age, pinned, creator-hearted and from-the-channel flags, plus optional replies. Top or newest order. No commenter names or handles are collected. Run again to see new comments and rank changes since the last run. No login.

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

## Pricing

from $0.40 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## YouTube Comments Scraper — Text, Likes & Replies, No Names

Give it a list of YouTube videos — watch links, `youtu.be` links, Shorts or plain video IDs — and get one clean row per comment: **text, likes, reply count, age, and whether it is pinned, hearted by the channel or written by the channel itself**, with the replies too if you want them. Top or newest order, up to 5,000 comments per video. **$0.50 per 1,000 comments**, no login, no API key — and **no commenter names, handles, channel IDs or avatars** are collected.

Run it again — or put it on a schedule — and every comment also tells you **what changed since the last run**: is it new, how far did it move up or down in the top order, how many likes did it gain. Each video also gets a free summary row with the number of new comments, which YouTube does not show you anywhere.

### What you get

| Field | What it is |
|---|---|
| `type`, `videoId`, `commentId`, `url` | the row type (`comment`), the video, the comment, and a link that opens that comment on YouTube |
| `text` | the comment text with **email addresses and phone numbers removed** and `@mentions` replaced by `@user` |
| `likes`, `likesRounded` | likes as YouTube shows them: exact below 1,000, rounded above ("4.8M" → `4800000`, `likesRounded` `true`) |
| `replyCount`, `replyCountRounded` | replies under the comment (`0` for a reply itself), rounded the same way above 999 |
| `publishedAgo`, `publishedDaysAgo`, `isEdited` | YouTube's own wording ("3 weeks ago"), an approximate day count (month = 30 days, year = 365), and whether it was edited |
| `isPinned`, `isCreator`, `isHearted` | pinned by the channel, written by the video's own channel, hearted by the channel |
| `isReply`, `parentCommentId` | `true` for a reply and the comment it belongs to (`null` on top-level comments) |
| `rank` | position in the list as read, 1 = first (top-level comments only; `null` on replies) |
| `isNewSinceLastRun`, `previousRank`, `rankChange`, `likesChangeSinceLastRun` | the change since your previous run of the same video and order (`null` on the first run) |
| `observedAt` | when the row was read |

Every video also gets one **free summary row** (`type` `video`): `videoId`, `url`, `title`, `channelName`, `commentCountShown` (the total YouTube shows, rounded above 999 and including replies), `commentCountRounded`, `commentsOff`, `sortUsed`, `commentsRead`, `topLevelRead`, `repliesRead`, `finished`, `stopReason` (`all-read`, `limit`, `comments-off`, `no-comments`, `stalled` or `error`), `newCommentsSinceLastRun` and `hoursSinceLastRun` (both `null` on the first run), `replyPagesFailed`, `note` (set when comments are off or the order you asked for was not offered), `input` (what you typed) and `observedAt`.

### Use it for

- **Audience research** — what people ask, praise and complain about under your videos or a competitor's, in their own words
- **Text analysis and AI pipelines** — clean comment text with no personal data to scrub afterwards
- **Tracking a launch or a controversy** — schedule it on the newest order and see how many new comments came in since the last run

### Input

```json
{ "videos": ["https://www.youtube.com/watch?v=jNQXAC9IVRw"], "maxCommentsPerVideo": 200, "sort": "top", "includeReplies": false, "maxRepliesPerComment": 10 }
```

- `maxCommentsPerVideo` — the most comments read per video (1–5,000, default 200). **Replies count toward it**, so it is also the most you can be charged for per video.
- `sort` — `top` (YouTube's default order) or `newest`. Use `newest` to track new comments.
- `includeReplies` / `maxRepliesPerComment` — also read the replies under each comment (oldest first), up to this many per comment.

What changed is remembered per video and order in a named key-value store in your Apify account, so the second run of the same Actor already shows changes. Schedule it (Apify → Schedules) to follow a video over time.

### Pricing

**$0.50 per 1,000 comments** (replies count as comments), plus $0.01 per run. A default run of 200 comments costs $0.11. The per-video summary rows and error rows (removed, private or mistyped videos) are free. The $0.01 run-start fee is the one charge every run pays, even one that returns nothing.

### Notes

- **Public data only, and no people.** What anyone sees under a video without signing in. Commenter names, `@handles`, channel IDs and profile pictures are never returned. The only identity in a row is `isCreator`: the comment was written by the video's own channel. Email addresses and phone numbers are removed from the text, and a `@handle` written in a comment becomes `@user`. A name at the start of a reply that matches a commenter of the same video becomes `@user` too. A name typed as ordinary words anywhere else in a comment cannot be recognised and stays in the text. Phone-number removal is deliberately greedy: a number written with spaces or dots between digit groups ("10 000 000", "100.000.000") looks like a phone number and is removed too.
- `likes` is exact below 1,000 and rounded above (YouTube writes "1.2K", "4.8M"). `likesChangeSinceLastRun` is only filled when both the previous and the current count are exact.
- `rank`, `previousRank` and `rankChange` mean something in the **top** order: `rankChange` is positive when the comment moved up. In the **newest** order a new comment pushes every other one down, so `rank` is just the position and the other two stay empty.
- `isNewSinceLastRun` is `true` for a comment that was not among those the previous run read. It is `null` where the previous run could not have seen it, for example comments 201 and beyond when the last run stopped at 200. In the top order a comment that climbed into the range you read also counts as new; for strict new-comment tracking use `newest`. A reply is only called new when the last run read that thread's replies to the end.
- The total in `commentCountShown` includes replies, and YouTube holds some comments for review or hides them, so the number you can read is usually lower. `finished` is `true` when the whole list was read; `stopReason` `limit` means it stopped at your `maxCommentsPerVideo`.
- A video with comments turned off (including videos made for kids) and a live stream with only live chat get a free summary row with `commentsOff` `true` and a `note`, and no comment rows. Live chat messages are not comments and are not read.
- Comment text longer than 10,000 characters is cut. Emoji come through as characters; stickers and images do not.
- `parentCommentId` is empty on top-level comments. `isHearted` is `true` when the channel gave the comment a heart.
- If YouTube stops answering part way, you keep the comments already read, get an error row (free) and a summary row with `stopReason` `error`. If it keeps refusing across several videos in a row, the Actor stops waiting and returns the remaining videos as free error rows; run it again later.

To follow the **video itself** — exact views, likes and views per day — see [YouTube Video Stats Tracker](https://apify.com/northbell/youtube-video-stats-tracker). To follow a **whole channel**, see [YouTube Channel Stats & Growth Tracker](https://apify.com/northbell/youtube-channel-growth-tracker).

### For AI agents

`{"videos": ["https://www.youtube.com/watch?v=jNQXAC9IVRw"], "maxCommentsPerVideo": 50}` returns up to 50 rows of `type` `comment` (text, likes, replyCount, publishedAgo) and one `video` summary row. Rows have `type`: `comment`, `video` or `error`. Pass several videos in one call to pay the run fee once, and set `sort` to `newest` with a schedule to get only what is new.

# Actor input Schema

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

One video per line: a youtube.com/watch link, a youtu.be link, a /shorts/ or /live/ link, or the 11-character video ID.

## `maxCommentsPerVideo` (type: `integer`):

Stop after this many comments for each video. Replies count toward it, so it is also the most you can be charged for per video. Videos with fewer comments return fewer.

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

Top = YouTube's default order (most liked and most discussed first). Newest = latest first, which is the one to use for tracking new comments.

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

Also read the replies under each comment (oldest first). Each reply is one more comment row and one more charge.

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

With 'Include replies' on: read at most this many replies under each comment. 0 reads none.

## Actor input object example

```json
{
  "videos": [
    "https://www.youtube.com/watch?v=jNQXAC9IVRw"
  ],
  "maxCommentsPerVideo": 200,
  "sort": "top",
  "includeReplies": false,
  "maxRepliesPerComment": 10
}
```

# Actor output Schema

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

Comment text, likes, reply counts, age, flags and the change since the last run.

## `videos` (type: `string`):

One summary row per video: comments read, comments YouTube shows, and how many are new since the last run.

# API

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

## JavaScript example

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

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

// Prepare Actor input
const input = {
    "videos": [
        "https://www.youtube.com/watch?v=jNQXAC9IVRw"
    ]
};

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

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

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

```

## Python example

```python
from apify_client import ApifyClient

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

# Prepare the Actor input
run_input = { "videos": ["https://www.youtube.com/watch?v=jNQXAC9IVRw"] }

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

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

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

```

## CLI example

```bash
echo '{
  "videos": [
    "https://www.youtube.com/watch?v=jNQXAC9IVRw"
  ]
}' |
apify call northbell/youtube-comments-scraper --silent --output-dataset

```

## MCP server setup

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