# YouTube Video & Shorts Comments Scraper with Replies (`heyitsgautham/youtube-comments-scraper`) Actor

Scrape comments and replies from YouTube videos and Shorts: text, author, likes, reply count, posted time, pinned and hearted flags. Top or newest order, only-new mode for scheduled runs. $0.25 per 1,000 comments, failures are free. Final test: all 68 videos with comments returned them.

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

## Pricing

from $0.18 / 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 Video & Shorts Comments Scraper with Replies

Get the comments and replies from any YouTube video or Short as clean rows, for sentiment analysis, audience research and brand monitoring.

Use cases, each with a ready-to-run example:

- [Export a video's comments together with their replies](https://apify.com/heyitsgautham/youtube-comments-scraper/examples/youtube-comments-with-replies)
- [Get the newest comments on several YouTube Shorts at once](https://apify.com/heyitsgautham/youtube-comments-scraper/examples/bulk-youtube-shorts-comments)
- [Build a comment dataset for sentiment analysis](https://apify.com/heyitsgautham/youtube-comments-scraper/examples/comments-for-sentiment-analysis)
- [Monitor only the comments from the last 7 days](https://apify.com/heyitsgautham/youtube-comments-scraper/examples/youtube-comments-last-7-days)
- [Collect comments on a channel's latest videos](https://apify.com/heyitsgautham/youtube-comments-scraper/examples/comments-on-channel-latest-videos)
- [Read what viewers say on the top videos for a search](https://apify.com/heyitsgautham/youtube-comments-scraper/examples/comments-on-youtube-search-results)

Paste video URLs or IDs, pick top or newest, and get one row per comment with the text, author, likes, reply count and posted time.
Or give a channel, a playlist or a search, and get the comments of its latest or top videos in one run.

You pay **$0.25 per 1,000 comments** ($0.00025 each), and less on Apify Store discount tiers (Bronze, Silver, Gold), down to $0.175 per 1,000 on Gold.
Replies count as comments.
Videos with comments turned off, deleted videos and failed fetches are **never charged**.

### At a glance

| Topic | Details |
|---|---|
| Input | YouTube video or Shorts URLs or IDs, and optionally channels, playlists and searches, each giving its latest or top videos |
| Output | One JSON row per comment or reply: text, author, likes, reply count, posted time, pinned and hearted flags, and the parent ID for replies |
| Price | $0.00025 per comment, replies included ($0.25 per 1,000), or $0.225 per 1,000 on Bronze, $0.20 on Silver and $0.175 on Gold. No start fee. Videos with no comments and failed fetches are free |
| Tested | Final test run on 80 videos, 17 of them Shorts: all 68 videos that had comments returned them, 4,366 rows in 4.5 minutes. A run on 57 channels, playlists and searches returned 14,127 rows from 161 videos in 2.5 minutes, and every listed video with comments returned them |
| Limits | `maxComments` is 100 per video by default, `0` takes every comment. Replies are off until you turn on `includeReplies`. YouTube rounds like counts of 1,000 and up |

### What you get per comment

| Field | What it holds |
|---|---|
| `videoId` | The video the comment belongs to |
| `commentId` | YouTube's comment ID. Replies look like `<parentId>.<replyId>` |
| `text` | The full comment text, with emoji and line breaks kept |
| `authorName`, `authorChannelId` | The commenter's handle and channel ID |
| `authorIsVerified`, `authorIsChannelOwner` | Verified badge, and whether the video's own channel wrote it |
| `likeCount` | Likes. YouTube rounds counts of 1,000 and up, so 325K comes back as `325000` |
| `replyCount` | Replies to this comment, as YouTube shows it |
| `publishedTimeText` | Posted time as YouTube shows it, such as `2 days ago` |
| `publishedAtApprox` | That time turned into a UTC timestamp at run time. Approximate: `2 days ago` can be up to a day earlier |
| `isEdited` | `true` when YouTube marks the comment as edited |
| `isReply`, `parentId` | `true` and the parent comment ID for replies. Replies come right after their parent |
| `isPinned`, `isHearted` | Pinned by the creator, and hearted by the creator |
| `commentUrl` | A direct link that opens the video at this comment |

With `includeVideoInfo` on, every row also carries three video fields right after `videoId`.

| Field | What it holds |
|---|---|
| `videoTitle` | The video's title |
| `videoViewCount` | The exact view count |
| `videoCommentCount` | The exact comment count YouTube shows, which includes replies |

Rows that come from a channel, playlist or search start with five more fields.

| Field | What it holds |
|---|---|
| `input` | The channel, playlist or search you gave |
| `sourceType` | `channel`, `playlist` or `search` |
| `sourceId` | The channel's `UC...` ID, the playlist ID or the search text |
| `sourceTitle` | The channel name, playlist title or search text |
| `position` | The video's place in the listing, 1 for the newest upload or the top search result |

A video that returns no comments gets one row with a `status` and a `message` instead.
That row is free.

| `status` | Meaning |
|---|---|
| `no_comments` | Comments are turned off, or nobody has commented yet. The message says which |
| `unavailable` | The video is deleted, private or the ID is wrong |
| `partial` | Some comments came back, but YouTube failed on a later page or on some reply threads. You pay only for the comments you got |
| `error` | YouTube kept failing for this video after 5 tries on fresh IPs |
| `invalid_input` | The input is not a YouTube link or video ID, or a channel field entry is not a channel or playlist link |
| `not_found` | The channel or playlist does not exist |
| `no_videos` | The channel, playlist or search has no public videos |

### Input

```json
{
  "videos": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://www.youtube.com/shorts/4z8Hi_uQOkE"
  ],
  "maxComments": 50,
  "sort": "top",
  "includeReplies": true,
  "maxRepliesPerComment": 10
}
```

| Option | Default | What it does |
|---|---|---|
| `videos` | | Watch, youtu.be, Shorts, embed and live links, or bare 11-character IDs. A video listed twice is scraped once |
| `channelsAndPlaylists` | empty | See Channels, playlists and search below |
| `searchQueries` | empty | See Channels, playlists and search below |
| `maxVideosPerSource` | 10 | Videos per channel, playlist or search |
| `includeShorts` | `false` | Channels only. Adds Shorts to the channel's videos |
| `maxComments` | 100 | Rows per video, replies included. `0` means every comment |
| `sort` | `top` | `top` is YouTube's default order. `newest` puts the latest comments first. Runs with `onlyNewSinceLastRun` on always read newest first |
| `includeReplies` | `false` | Adds replies after each parent comment |
| `maxRepliesPerComment` | 10 | Reply cap per thread. `0` means all replies |
| `includeVideoInfo` | `false` | Adds `videoTitle`, `videoViewCount` and `videoCommentCount` to every row, at no extra cost |
| `onlyNewSinceLastRun` | `false` | See Monitoring below |
| `publishedAfter` | empty | See Monitoring below |

### Channels, playlists and search

Besides `videos`, two optional inputs take comments from many videos at once.

| Input | What it takes |
|---|---|
| `channelsAndPlaylists` | Channel links in any form (`@handle`, `/channel/UC...`, `/c/name`, `/user/name`), playlist links with `list=...`, and bare `@handles`, `UC...` channel IDs or `PL...` playlist IDs. A channel gives its latest videos, a playlist its first ones |
| `searchQueries` | YouTube searches, each giving its top videos in YouTube's order |
| `maxVideosPerSource` | How many videos to take from each channel, playlist or search. Default 10, `0` means all, up to 20,000 |
| `includeShorts` | Channels only. Off: regular videos and past live streams. On: every upload, Shorts included |

`maxComments` still applies to each video, so 10 videos at the default 100 comments give up to 1,000 rows per channel.
Listing a channel, a playlist or a search is free, and you pay only for comments.
A video met twice in one run, through `videos` or another source, is scraped and charged once.
A channel or playlist that does not exist comes back as one free `not_found` row, and a video with comments off as a free `no_comments` row with its source fields.

```json
{
  "channelsAndPlaylists": ["@3blue1brown", "https://www.youtube.com/playlist?list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab"],
  "searchQueries": ["receta de paella"],
  "maxVideosPerSource": 3,
  "maxComments": 100,
  "includeVideoInfo": true
}
```

### Monitoring: only new comments and a date cutoff

Two optional inputs turn a scheduled run into a feed of new comments.
Both are off by default, and a run without them works exactly as before.

| Option | What it does |
|---|---|
| `onlyNewSinceLastRun` | Returns only comments this scraper has not returned to you before for the same video and filters, and nothing older than the newest one it returned last time. The first run returns the newest comments up to `maxComments` and remembers them |
| `publishedAfter` | Only comments published on or after a date: `2026-10-01`, `2026-10-01T12:00:00Z` (UTC), or a relative value such as `7 days` |

With `onlyNewSinceLastRun` on, the run reads comments newest first whatever `sort` says.
It stops at the first page that holds nothing new, so a daily run reads only the pages it needs.
A `publishedAfter` cutoff on its own stops early only with `sort: "newest"`, and in top order it reads further to find newer comments.
You pay only for the comments returned.
YouTube shows only relative times such as `3 days ago`, so `publishedAfter` works on an approximate time, given on every row as `publishedAtApprox`.
The real time can be up to one unit earlier, up to a day for `3 days ago`.
When the run stops early, new replies on older comment threads are not picked up.
The memory is a key-value store named `youtube-comments-scraper-monitor` in your own Apify account, one record per video and replies setting.
Delete that store to start over.
A video with nothing new comes back as a free `no_comments` row.
The memory belongs to the video, not to the way you reached it, so a video you monitored through `videos` keeps its memory when it comes from a channel, a playlist or a search instead.
A scheduled run on a channel lists its latest videos each time, and a newly uploaded video returns its newest comments up to `maxComments` on its first run.

### Run it on a schedule

A daily run with `onlyNewSinceLastRun: true` gives you the new comments on the videos or channels you watch.
We ran the same 60 videos on 15 Oct and again on 20 Oct.
The 20 Oct run returned 925 comments and replies, and a script found none that the 15 Oct runs had returned.
25 videos with nothing new came back as free `no_comments` rows.

1. Set your input with `onlyNewSinceLastRun: true` and click **Save as a new task**.
2. On the task page, click **Actions**, then **Schedule**, and pick how often it runs.
   [Apify's schedules guide](https://docs.apify.com/actors/running/schedules) covers cron times and time zones.
3. On the task's **Integrations** tab, choose where each run's results go.

| Integration | What it does |
|---|---|
| [Slack](https://docs.apify.com/integrations/slack) | Posts a message to your channel when a run finishes |
| [Google Drive](https://docs.apify.com/integrations/drive) | Saves each run's results as a file in your Drive |
| [Webhook](https://docs.apify.com/integrations/webhooks) | Sends the finished run, with its dataset ID, to your own URL |
| [Make](https://docs.apify.com/integrations/make), [Zapier](https://docs.apify.com/integrations/zapier), [n8n](https://docs.apify.com/integrations/n8n) | Adds each new row to a Google Sheet, a CRM or a database |

Each comment has a stable `commentId`, so a sheet or database can skip rows it already holds.

### Output example

This is real output for the input above, from a run on 15 Oct 2026.
It shows the first comment on the first video and its first reply.

```json
[
  {
    "videoId": "dQw4w9WgXcQ",
    "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?",
    "authorName": "@candycake9531",
    "authorChannelId": "UCNLgzvqrGzFi5SEAbVkFchg",
    "authorIsVerified": false,
    "authorIsChannelOwner": false,
    "likeCount": 291000,
    "replyCount": 675,
    "publishedTimeText": "6 years ago",
    "publishedAtApprox": "2020-10-15T06:16:44Z",
    "isEdited": false,
    "isReply": false,
    "parentId": null,
    "isPinned": false,
    "isHearted": false,
    "commentUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ&lc=Ugxzbv_ZeZXNRcfwsSF4AaABAg"
  },
  {
    "videoId": "dQw4w9WgXcQ",
    "commentId": "Ugxzbv_ZeZXNRcfwsSF4AaABAg.91_2FL04Xww97FrL-edZw3",
    "text": "@Sam The Gamer?",
    "authorName": "@candycake9531",
    "authorChannelId": "UCNLgzvqrGzFi5SEAbVkFchg",
    "authorIsVerified": false,
    "authorIsChannelOwner": false,
    "likeCount": 4300,
    "replyCount": 0,
    "publishedTimeText": "6 years ago",
    "publishedAtApprox": "2020-10-15T06:16:45Z",
    "isEdited": true,
    "isReply": true,
    "parentId": "Ugxzbv_ZeZXNRcfwsSF4AaABAg",
    "isPinned": false,
    "isHearted": false,
    "commentUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ&lc=Ugxzbv_ZeZXNRcfwsSF4AaABAg.91_2FL04Xww97FrL-edZw3"
  }
]
```

This row comes from the final test run on 17 Oct 2026, with `@3blue1brown` in `channelsAndPlaylists`, `maxVideosPerSource: 3` and `includeVideoInfo: true`.

```json
{
  "input": "@3blue1brown",
  "sourceType": "channel",
  "sourceId": "UCYO_jab_esuFRV4b17AJtAw",
  "sourceTitle": "3Blue1Brown",
  "position": 1,
  "videoId": "LKrwhjOI8Nc",
  "videoTitle": "There's never been a better time to go into math",
  "videoViewCount": 852735,
  "videoCommentCount": 2543,
  "commentId": "UgwyDGkk9dXgW3_c-UV4AaABAg",
  "text": "Final year of my math degree this is what happens. Incredible comedic timing can't even be mad",
  "authorName": "@blazednewt413",
  "authorChannelId": "UCObAuvVyGm0VE33DT8G57zA",
  "authorIsVerified": false,
  "authorIsChannelOwner": false,
  "likeCount": 452,
  "replyCount": 32,
  "publishedTimeText": "10 hours ago",
  "publishedAtApprox": "2026-10-16T17:18:58Z",
  "isEdited": false,
  "isReply": false,
  "parentId": null,
  "isPinned": false,
  "isHearted": false,
  "commentUrl": "https://www.youtube.com/watch?v=LKrwhjOI8Nc&lc=UgwyDGkk9dXgW3_c-UV4AaABAg"
}
```

A channel that does not exist returns this free row:

```json
{
  "input": "https://www.youtube.com/@thisHandleDoesNotExist_zq81x",
  "status": "not_found",
  "message": "YouTube says this channel or playlist does not exist"
}
```

A video with comments turned off returns this free row:

```json
{
  "input": "https://youtu.be/XqZsoesa55w",
  "videoId": "XqZsoesa55w",
  "status": "no_comments",
  "message": "Comments are turned off for this video",
  "commentsReturned": 0
}
```

### How well it works

We tested the final build on 80 different videos in one run: music videos, podcasts, news in Tamil and Hindi, live stream replays, sports highlights, small channels and 17 Shorts.

- All 68 videos that had comments returned them, 4,366 comments and replies in total.
- 8 videos had comments turned off and 3 had no comments yet. Each got a free `no_comments` row.
- 1 made-up video ID got a free `unavailable` row.
- The run took 4.5 minutes with 100 comments per video and up to 5 replies per thread.

A second run on 17 Oct 2026 took 3 videos from each of 30 channels, 12 playlists and 15 searches, in English, Spanish, French and Hindi, with `includeVideoInfo` on.

- 56 of the 57 sources returned comments, 14,127 rows from 161 videos, in 2.5 minutes.
- The other source is NASA, whose 3 latest videos all have comments turned off.
- 7 videos had comments turned off and 2 had no comments yet, each with a free `no_comments` row.
- Every one of the 161 videos came back with its title, view count and comment count.
- A made-up handle got a free `not_found` row, and a video link in the channel field a free `invalid_input` row.

In a separate check with no limits, 20 of these videos with fewer than 100 comments returned within 3 rows of the comment count YouTube shows.
The small gap comes from comments YouTube still counts but no longer shows, such as held or deleted ones.

### Use it from AI agents

The scraper works as a tool through the [Apify MCP server](https://mcp.apify.com) in Claude, Cursor, VS Code and other MCP clients.
An agent can pass a video link and get back the comments as text it can summarise or classify.

You can also call it through the [Apify API](https://docs.apify.com/api/v2) or the Python and JavaScript clients, and schedule it or connect it to Make, Zapier and n8n.

### Pricing

Prices are per 1,000 comments.

| Event | No discount | Bronze | Silver | Gold |
|---|---|---|---|---|
| Comment or reply returned | $0.25 | $0.225 | $0.20 | $0.175 |
| Comments off, no comments, unavailable video, invalid input or failed fetch | Free | Free | Free | Free |

Bronze, Silver and Gold are Apify Store discount tiers, and Apify's Pricing tab shows them as Starter, Scale and Business.
Apify decides which tier an account is on.

Set a maximum cost per run in the run options.
The scraper stops once that limit is reached.

### More from heyitsgautham

Other actors from the same account.

- [YouTube Transcript & Subtitles Scraper](https://apify.com/heyitsgautham/youtube-transcript-scraper) for specific videos, or when you want every video on a channel or playlist with channel stats and up to 20,000 videos per source.
- [YouTube Channel & Playlist Transcripts](https://apify.com/heyitsgautham/youtube-channel-transcripts) for every video on a channel or playlist, with channel stats and up to 20,000 videos per source.
- [YouTube Search Results & Rank Tracker Scraper](https://apify.com/heyitsgautham/youtube-search-scraper) for YouTube search results with rank, and channel discovery within a subscriber range.
- [YouTube & TikTok Transcripts MCP Server for AI Agents](https://apify.com/heyitsgautham/video-transcripts-mcp-server) for giving an AI agent YouTube and TikTok transcripts, YouTube search and comments as MCP tools, with nothing to host.

### FAQ

**Why did I get fewer comments than the video shows?**
The count on YouTube includes replies, and replies are off by default.
Turn on `includeReplies` and set `maxRepliesPerComment` to `0` to get all of them.

**Why is the first comment in newest order an old one?**
YouTube always puts the pinned comment first, in both orders.

**Why do some Top results look like Newest?**
On some videos YouTube now limits Top to a few comments the creator featured.
When that happens the scraper switches that video to newest order so you still get every comment.

**Does it work for Shorts and live streams?**
Yes.
Shorts and finished live streams have the same comments as normal videos.
Live chat messages are not comments and are not included.

**Are the dates exact?**
No.
YouTube only shows relative times such as `3 weeks ago`, and the scraper returns them as shown.

**Does it use the official YouTube API?**
No.
It reads the same public comment data the YouTube website shows to logged-out visitors, with no login and no API key.
It does not collect emails or phone numbers.

### Limitations

- Like counts of 1,000 and up are rounded by YouTube, so `1.2K` becomes `1200`.
- `replyCount` can be a little higher than the replies you get, because YouTube counts held and deleted replies.
- Rows from several videos can interleave in the dataset. Group by `videoId` if you need them apart.
- A channel or playlist link put in `videos` comes back as a free `invalid_input` row whose message points to `channelsAndPlaylists`.
- Mixes (`list=RD...`) cannot be listed.

# Actor input Schema

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

Video URLs or 11-character video IDs. Accepts watch, youtu.be, Shorts, embed and live links. For the latest videos of a channel or playlist, or the top videos of a search, use the next two fields.

## `channelsAndPlaylists` (type: `array`):

Optional. YouTube channel or playlist URLs. The scraper takes the latest videos of each channel, or the first videos of each playlist, and scrapes their comments. Accepts @handle, /channel/UC..., /c/... and /user/... links, playlist links with list=..., and bare @handles, UC channel IDs or PL playlist IDs. Listing the videos is free, and each comment is charged as usual.

## `searchQueries` (type: `array`):

Optional. YouTube searches. The scraper takes the top videos of each search in YouTube's order and scrapes their comments. The search is free, and each comment is charged as usual.

## `maxVideosPerSource` (type: `integer`):

How many videos to take from each channel, playlist or search. Channels go newest first. 0 means all videos, up to 20,000. Max comments per video still applies to each one. Does not limit the videos field.

## `includeShorts` (type: `boolean`):

Channels only. Off: regular videos and past live streams. On: every upload, Shorts included.

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

Stop after this many rows per video. Replies count toward the limit. Set 0 to get every comment.

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

Top comments is YouTube's default order. Runs with Only new since the last run on always read newest first.

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

Adds replies right after their parent comment, with isReply set to true and parentId pointing to the parent.

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

Caps replies per comment thread when replies are on. Set 0 for all replies.

## `includeVideoInfo` (type: `boolean`):

Adds videoTitle, videoViewCount and videoCommentCount to every comment row, right after videoId. videoCommentCount is the exact count YouTube shows, which includes replies. Free, and each comment costs the same.

## `onlyNewSinceLastRun` (type: `boolean`):

For scheduled runs. Returns only comments and replies this actor has not returned to you before for the same video and filters, and nothing older than the newest one it returned last time. These runs read comments newest first whatever Sort by says, and stop at the first page with nothing new. The first run returns the newest comments up to your limit and remembers them. The memory is a key-value store named youtube-comments-scraper-monitor in your Apify account.

## `publishedAfter` (type: `string`):

Only comments and replies published on or after this date. Use a date such as 2026-10-01, an ISO time such as 2026-10-01T12:00:00Z (UTC), or a relative value such as 7 days, meaning the last 7 days. With newest-first order the run stops as soon as it reaches older ones. YouTube shows only relative times such as 3 days ago, so this cutoff is approximate, to within one unit of that time.

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

How many videos to fetch in parallel.

## `useProxy` (type: `boolean`):

Leave on. YouTube blocks cloud IPs.

## Actor input object example

```json
{
  "videos": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "https://www.youtube.com/shorts/4z8Hi_uQOkE"
  ],
  "maxVideosPerSource": 10,
  "includeShorts": false,
  "maxComments": 50,
  "sort": "top",
  "includeReplies": true,
  "maxRepliesPerComment": 10,
  "includeVideoInfo": false,
  "onlyNewSinceLastRun": false,
  "maxConcurrency": 10,
  "useProxy": true
}
```

# Actor output Schema

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

One row per comment or reply with text, author, likes, reply count, posted time and pinned and hearted flags. Videos with no comments get one uncharged row with a status and a note.

# 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",
        "https://www.youtube.com/shorts/4z8Hi_uQOkE"
    ],
    "maxComments": 50,
    "includeReplies": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("heyitsgautham/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",
        "https://www.youtube.com/shorts/4z8Hi_uQOkE",
    ],
    "maxComments": 50,
    "includeReplies": True,
}

# Run the Actor and wait for it to finish
run = client.actor("heyitsgautham/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",
    "https://www.youtube.com/shorts/4z8Hi_uQOkE"
  ],
  "maxComments": 50,
  "includeReplies": true
}' |
apify call heyitsgautham/youtube-comments-scraper --silent --output-dataset

```

## MCP server setup

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