# YouTube Comments Scraper (no login, text + likes, monitor) (`datahamster/youtube-comments`) Actor

Get YouTube video comments without login: text, like count, reply count and pin/heart status for a list of videos. No author names, channel ids or avatars collected. Monitor mode alerts on new comments; pay only per comment returned.

- **URL**: https://apify.com/datahamster/youtube-comments.md
- **Developed by:** [Viktor Dubnytskiy](https://apify.com/datahamster) (community)
- **Categories:** Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.40 / 1,000 result items

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 (no login, text + likes, monitor)

Get the top-level comments of any YouTube video: text, like count, reply count, pin/heart status and a relative +
estimated publish date. No YouTube account, no cookies, no API key. Runs the same Innertube endpoint the official
Android app uses.

### What you get

Real rows from the example dataset (video `dQw4w9WgXcQ`):

| text | likeCount | replyCount | publishedText | isPinned / isHearted |
|---|---|---|---|---|
| "can confirm: he never gave us up" | `318000` | `962` | `1 year ago` | `true` / `true` |
| "I Rick rolled my entire French class because we had to study a city in France…" | `101000` | `548` | `6 years ago (edited)` | `false` / `false` |
| "Gonna flag this for nudity so I can rick roll the YouTube staff" | `566000` | `700` | `6 years ago` | `false` / `false` |

Full row: `id`, `url`, `videoId`, `videoUrl`, `text`, `likeCount`, `replyCount`, `publishedText`, `publishedAt`, `isPinned`, `isHearted`, `isReply`, `query`, `scrapedAt`.

**Not collected, ever:** commenter display name, channel id/handle, avatar image, verification/creator badges. Only
the comment content and its counters.

### Use cases

- Read sentiment and reactions on your own or a competitor's video without opening YouTube.
- Track how many likes a pinned comment collects over time (monitor mode).
- Feed comment text into a summariser or moderation pipeline.

### Try it in 10 seconds

Hit **Start**/**Try it** — the input already works: `videoUrls: ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"]`, `maxCommentsPerVideo: 100`, `maxItems: 200`, nothing required.

To track a video's comment section over time: save the task, set **Mode** to `monitor`, and put it on a schedule (Apify → Schedules → cron `0 */6 * * *` every 6 hours). Each run then returns only comments that are new since the previous check.

### How it works

1. **Entry** — the video's Innertube `next` response carries the comment section's continuation token, if the
   video has comments open at all.
2. **Pages** — each continuation page returns up to ~20 comments with their like/reply counters, pin status and
   whether the creator hearted them; the actor walks continuations until `maxCommentsPerVideo` is reached, a page
   repeats the same ids, or comments run out.
3. Comments turned off (private uploads, some made-for-kids videos) or an invalid video id come back as a normal
   empty result for that video — not a block, not a charge. If every proxy tier YouTube answers with a wall for a
   video, the run stops and reports a block instead of silently returning nothing.

### Input

| Field | Meaning | Default |
|---|---|---|
| `videoUrls` | Video URLs (`watch?v=`, `youtu.be/…`, `/shorts/…`) or bare 11-character ids | required |
| `maxCommentsPerVideo` | Stop fetching comments for one video after this many | `100` |
| `sort` | `top` or `newest` — see Limits, only `top` is actually served | `top` |
| `maxItems` | Stop the whole run after this many comment rows | `200` |
| `mode` | `scrape` or `monitor` (only new comments since last run) | `scrape` |
| `monitorStateId`, `webhookUrl`, `telegramBotToken`, `telegramChatId` | Monitor-mode state key and alert targets | empty |

### Pricing

| Event | Price |
|---|---|
| result | $0.0005 per comment ($0.50 per 1,000) |
| monitor-check | $0.005 per monitor run |
| change | $0.0005 per new comment |

Charged only for comments actually pushed. Residential proxy traffic is billed by Apify on top of these prices
when YouTube walls the datacenter tier.

### Why this actor

- No login, no cookies, no API key or quota to manage.
- Comment counters (likes, replies) alongside the text in one row — most comment scrapers on the Store return text
  only.
- A run that finds nothing pushes nothing and charges no result events; the run summary explains why.

### Limits

- **Top-level comments only.** Replies are not expanded in this version; `isReply` is always `false`.
- **Sort order.** YouTube's Android client (the one this actor reads) does not expose the "Newest first" sort
  chips in its response, only the default "Top comments" order. `sort: "newest"` is accepted on input for forward
  compatibility but every run currently returns the same top-comments order.
- **`publishedAt` is an estimate**, computed from YouTube's own relative text ("1 year ago") at scrape time, not an
  exact timestamp.
- **Live/upcoming streams and members-only comments** are not specifically handled and may return fewer rows than
  expected.

### FAQ

**Does it need a YouTube account or cookies?** No — every request is made as a logged-out Android app client.

**Why is there no commenter name or avatar?** By design: this actor collects comment content and counters only,
never person-level identity of individual commenters.

**What happens when comments are off for a video?** No rows are pushed for that video and nothing is charged; the
run continues with the rest of `videoUrls`.

### Changelog

- 0.1: initial release — top-level comments with text, counters, pin/heart status and an estimated publish date;
  monitor mode; walled videos are reported as a block instead of an empty dataset.

***

If this actor saved you time, a short review on its Store page genuinely helps other people find it. Found a bug
or need a field that is missing? Open a ticket on the **Issues** tab.

# Actor input Schema

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

Stop after this many results (you are charged only for pushed items)

## `mode` (type: `string`):

scrape = full results; monitor = only new/changed items since the previous run of this task

## `monitorStateId` (type: `string`):

Optional state id when not running as a saved task (monitor mode)

## `webhookUrl` (type: `string`):

POST a change summary here in monitor mode

## `telegramBotToken` (type: `string`):

Optional: bot token for monitor-mode change summaries

## `telegramChatId` (type: `string`):

Optional: chat id that receives monitor-mode summaries

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

YouTube video URLs (watch?v=..., youtu.be/..., /shorts/...) or bare 11-character video ids, one per line.

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

Stop fetching comments for one video after this many, e.g. 100.

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

Requested sort order. Only "top" is currently served by the source; see the README Limits section.

## Actor input object example

```json
{
  "maxItems": 200,
  "mode": "scrape",
  "videoUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "maxCommentsPerVideo": 100,
  "sort": "top"
}
```

# Actor output Schema

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

All pushed rows (dataset, JSON)

## `resultsTable` (type: `string`):

Dataset in the Console viewer

## `runSummary` (type: `string`):

RUN\_SUMMARY record

# 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=dQw4w9WgXcQ"
    ],
    "maxCommentsPerVideo": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("datahamster/youtube-comments").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=dQw4w9WgXcQ"],
    "maxCommentsPerVideo": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("datahamster/youtube-comments").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=dQw4w9WgXcQ"
  ],
  "maxCommentsPerVideo": 100
}' |
apify call datahamster/youtube-comments --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datahamster/youtube-comments"
        }
    }
}
```

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/pvgIfhy0REGCRUzJa/builds/0kfNyTRrBrBGOL2e4/openapi.json
