# YouTube Comments $0.4/1k: Replies & Shorts (`wiseus-labs/youtube-comments-scraper`) Actor

$0.40 per 1,000 comments, failed and empty videos are free. Scrape YouTube comments and replies from videos and Shorts with likes, pins and creator hearts.

- **URL**: https://apify.com/wiseus-labs/youtube-comments-scraper.md
- **Developed by:** [Wiseus Labs](https://apify.com/wiseus-labs) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

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

### 💬 What you get

Paste YouTube video or Shorts links and get every comment as a row in a dataset: the comment text, author handle and channel ID, like count, reply count, relative publish time, and whether the comment is pinned, hearted by the creator, or written by the channel owner. Replies can be included and come right after their parent comment. You pay $0.40 per 1,000 comments. Videos with comments turned off, no comments, or a broken link cost nothing.

Example output from [this video](https://www.youtube.com/watch?v=yFuTAKq_j3Q): a top-level comment and the creator's reply to it.

```json
[
  {
    "videoId": "yFuTAKq_j3Q",
    "videoUrl": "https://www.youtube.com/watch?v=yFuTAKq_j3Q",
    "commentId": "UgxxZvmMljCcyZGlarl4AaABAg",
    "text": "Noice video.\nI recently discovered Homer and prefer it to Heimdall because there is no need for user credentials...",
    "authorName": "@Clarence-Homelab",
    "authorChannelId": "UC8VjOuewZxnD2nv9jIDwjww",
    "authorIsChannelOwner": false,
    "likeCount": 1,
    "likeCountText": "1",
    "replyCount": 1,
    "publishedTimeText": "5 years ago",
    "isPinned": false,
    "isHeartedByCreator": false,
    "isReply": false,
    "parentCommentId": null,
    "status": "ok"
  },
  {
    "videoId": "yFuTAKq_j3Q",
    "videoUrl": "https://www.youtube.com/watch?v=yFuTAKq_j3Q",
    "commentId": "UgxxZvmMljCcyZGlarl4AaABAg.9SCVE2vlgTC9SCVgAAeHV9",
    "text": "Nice, I'll be sure to check it out",
    "authorName": "@RaidOwl",
    "authorChannelId": "UC9evhW4JB_UdXSLeZGy8lGw",
    "authorIsChannelOwner": true,
    "likeCount": 0,
    "likeCountText": "",
    "replyCount": 0,
    "publishedTimeText": "5 years ago",
    "isPinned": false,
    "isHeartedByCreator": false,
    "isReply": true,
    "parentCommentId": "UgxxZvmMljCcyZGlarl4AaABAg",
    "status": "ok"
  }
]
```

### ⚙️ Input

| Field | Type | Default | Description |
|---|---|---|---|
| `videos` | array of strings | one example video | Video URLs or IDs. Accepts `youtube.com/watch?v=...`, `youtu.be/...`, `/shorts/...`, `/embed/...`, `/live/...`, `m.youtube.com` links and bare 11-character IDs. Duplicates are removed. |
| `maxCommentsPerVideo` | integer | 100 | Maximum rows per video, comments and replies together. 0 = no limit. |
| `sortBy` | `top` or `newest` | `top` | Order of top-level comments. |
| `includeReplies` | boolean | false | Also save replies. Each reply follows its parent comment. |
| `maxRepliesPerComment` | integer | 20 | Maximum replies saved per comment. 0 = all replies. |
| `maxConcurrency` | integer | 5 | Number of videos processed at the same time (1 to 20). |

Example input:

```json
{
  "videos": [
    "https://www.youtube.com/watch?v=yFuTAKq_j3Q",
    "https://www.youtube.com/shorts/M93h41hyPsM",
    "dQw4w9WgXcQ"
  ],
  "maxCommentsPerVideo": 500,
  "sortBy": "newest",
  "includeReplies": true,
  "maxRepliesPerComment": 20
}
```

### 📋 Output fields

One row per comment or reply.

| Field | Description |
|---|---|
| `videoId` | YouTube video ID. |
| `videoUrl` | Link to the video. |
| `commentId` | Comment ID. A reply ID has the form `<parentCommentId>.<suffix>`. |
| `text` | Comment text. Empty for comments that contain only an image. |
| `authorName` | Author handle, for example `@RaidOwl`. |
| `authorChannelId` | Author channel ID. |
| `authorIsChannelOwner` | `true` if the video's channel wrote the comment. |
| `likeCount` | Likes as a number, parsed from the rounded figure YouTube shows: "1.2K" becomes 1200. YouTube does not show exact like counts for comments. |
| `likeCountText` | Likes exactly as YouTube shows them, for example "1.2K". Empty when there are no likes. |
| `replyCount` | Number of replies to the comment. Always 0 for replies. |
| `publishedTimeText` | Relative publish time, for example "3 years ago", with "(edited)" added for edited comments. YouTube does not show exact dates for comments. |
| `isPinned` | `true` if the creator pinned the comment. |
| `isHeartedByCreator` | `true` if the creator gave the comment a heart. |
| `isReply` | `true` for replies. |
| `parentCommentId` | For replies, the ID of the comment they answer. `null` for top-level comments. |
| `status` | `ok` for comment rows. Other values mark status rows, see below. |

You can export the dataset as JSON, CSV, Excel, XML or HTML, or read it through the Apify API.

### 🚦 Status rows

When a video gives no comments, you get one row that says why, so every input is accounted for. Status rows have `videoId`, `videoUrl`, `status` and `reason`, and they are free.

| `status` | When it appears |
|---|---|
| `comments_disabled` | The creator turned comments off, for example on videos made for kids. |
| `no_comments` | The video exists and allows comments but has none yet. |
| `unavailable` | The video does not exist, was removed, or cannot be watched. |
| `invalid_input` | The input entry is not a YouTube video link or ID. `videoUrl` holds the entry as you typed it. |
| `error` | The video could not be read to the end. Comments collected before the error are kept, and `reason` says what went wrong. |
| `run_summary` | The whole run produced no comments. One row explains why. |

### 💰 Pricing

You pay per comment: $0.0004 per comment or reply, which is $0.40 per 1,000. There is no start fee, and you are not charged for compute.

| Run | Cost |
|---|---|
| 1,000 comments | $0.40 |
| 100 videos x 100 comments | $4.00 |
| 50 videos with comments turned off | $0.00 |

To cap what a run can cost, set "Maximum cost per run" in the run options. When the limit is reached, the run stops cleanly and keeps everything collected so far.

### 🔀 Sorting and replies

**Sorting.** `top` returns comments in YouTube's "Top comments" order. That order can leave out some low-engagement comments: on one test video, Top returned 99 top-level comments and Newest returned all 106. Use `newest` when you need the complete set.

**Replies.** Popular comments can have hundreds of replies. Without a cap, a few long threads would use up `maxCommentsPerVideo` before you see many top-level comments. `maxRepliesPerComment` (default 20) keeps a sample of each thread and leaves room for more top-level comments. Set it to 0 to save every reply.

### 🎯 Common uses

- Sentiment analysis of reactions to a video, product launch or announcement.
- Audience research: what viewers like, dislike and ask for.
- Brand monitoring on videos that mention your product.
- Competitor research on other channels' videos and their audiences.
- Training and test data for NLP models: real, informal text with like counts.
- Finding viewer questions to answer in new videos or FAQs.

### ❓ FAQ

**Do I need a YouTube API key or a Google login?**
No. Paste video links and run.

**Does it work with YouTube Shorts?**
Yes. Use the Shorts link (`youtube.com/shorts/...`) or the video ID.

**How do I export the comments?**
Open the run's dataset in Apify Console and download it as JSON, CSV, Excel, XML or HTML, or fetch it with the Apify API.

**How do I get all comments of a video?**
Set `maxCommentsPerVideo` to 0, `sortBy` to `newest`, `includeReplies` to true and `maxRepliesPerComment` to 0.

**Why is `likeCount` a round number?**
YouTube shows comment likes rounded ("12K"), and no exact figure is available. `likeCount` is that figure as a number; `likeCountText` is the original text.

**Why is there no exact comment date?**
YouTube only shows relative times such as "3 years ago" for comments. `publishedTimeText` gives that text as shown.

**Am I charged for videos that have no comments?**
No. Only comment rows (`status` = `ok`) are charged.

# Actor input Schema

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

YouTube video or Shorts links, or 11-character video IDs. Duplicates are removed. Entries that are not YouTube videos are reported as "invalid_input" rows and are free.

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

Maximum rows saved per video, comments and replies together. 0 = no limit.

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

Order of top-level comments. "Top comments" can leave out some low-engagement comments; "Newest first" returns all of them.

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

Also save replies. Each reply follows its parent comment.

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

Maximum replies saved per comment when "Include replies" is on, so long threads do not use up the per-video limit. 0 = all replies.

## `maxConcurrency` (type: `integer`):

Number of videos processed at the same time.

## Actor input object example

```json
{
  "videos": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "maxCommentsPerVideo": 100,
  "sortBy": "top",
  "includeReplies": false,
  "maxRepliesPerComment": 20,
  "maxConcurrency": 5
}
```

# Actor output Schema

## `comments` (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 = {
    "videos": [
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    ],
    "maxCommentsPerVideo": 100
};

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

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

```

## MCP server setup

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