Scrape YouTube comments to CSV for audience and sentiment analysis
Marketers, product teams and researchers read YouTube comments to learn what viewers ask, praise and complain about. Copying comments by hand does not scale past one video.
arcadium/youtube-comments takes video or Shorts links and returns one row per comment: text, likes, reply count, date, pinned, creator-heart and by-creator flags, with the video title and channel. Replies are optional and come right after their comment. Comment authors’ names and handles are never collected.
Cost of this example on the Apify Free plan: 900 × $0.0018 = $1.62 ($0.729 on the Apify Gold plan and higher), plus $0.001 per GB of memory when the run starts.
What you need
- An Apify account and API token (no Google API key needed).
- The video or Shorts links, or 11-character video ids.
Step 1: Run it in the Apify Store (no code)
- Open arcadium/youtube-comments on the Apify Store and sign in (a free Apify account works).
- Paste the video links into Videos, one per line.
- Set Max comments per video, for example 300 (comments plus replies).
- Pick
TOP_COMMENTSorNEWEST_FIRSTunder Sort order. - Turn on Include replies and set Max replies per comment, for example 5.
- Optional: set a maximum cost per run in the run options as a hard cap.
- Click Start. Rows appear in the Output tab; export them as JSON, CSV or Excel.
The same input as JSON (paste it in the JSON tab of the input form):
{
"urls": [
"https://www.youtube.com/watch?v=dQw4w9WgXcQ"
],
"maxComments": 300,
"sortCommentsBy": "TOP_COMMENTS",
"includeReplies": true,
"maxRepliesPerComment": 5
}
Step 2: Call it over the Apify API
One HTTP call runs the actor and returns its rows. It suits runs up to about five minutes; for longer runs start the run asynchronously and read the dataset when it finishes.
curl -X POST "https://api.apify.com/v2/acts/arcadium~youtube-comments/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"urls":["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],"maxComments":300,"sortCommentsBy":"TOP_COMMENTS","includeReplies":true,"maxRepliesPerComment":5}'
Step 3: Run it from Python
With apify-client 3.x, call() returns a Run object: read the dataset id as run.default_dataset_id (older examples use run["defaultDatasetId"], which no longer works).
# pip install "apify-client>=3"
import csv, os
from apify_client import ApifyClient
videos = [
"https://www.youtube.com/watch?v=dQw4w9WgXcQ",
# add more video or Shorts links here
]
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("arcadium/youtube-comments").call(run_input={
"urls": videos, "maxComments": 300, "sortCommentsBy": "TOP_COMMENTS",
"includeReplies": True, "maxRepliesPerComment": 5,
})
rows = list(client.dataset(run.default_dataset_id).iterate_items()) # apify-client 3.x
keys = ["videoId", "videoTitle", "commentId", "isReply", "parentCommentId", "text", "likeCount",
"replyCount", "publishDate", "isPinned", "isHearted", "isByChannelOwner", "commentUrl"]
with open("youtube-comments.csv", "w", newline="", encoding="utf-8") as f:
w = csv.DictWriter(f, fieldnames=keys, extrasaction="ignore")
w.writeheader()
w.writerows(r for r in rows if r.get("rowType") == "comment")
for e in (r for r in rows if r.get("rowType") == "error"):
print("no comments:", e.get("input"), e.get("code"), e.get("message"))
Step 4: Run it from JavaScript
// npm install apify-client
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('arcadium/youtube-comments').call({
"urls": [
"https://www.youtube.com/watch?v=dQw4w9WgXcQ"
],
"maxComments": 300,
"sortCommentsBy": "TOP_COMMENTS",
"includeReplies": true,
"maxRepliesPerComment": 5
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
Step 5: Ask an AI assistant (MCP)
Apify’s hosted MCP server turns the actor into one tool. Add it to Claude, Cursor, VS Code or any MCP client:
{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com/?tools=arcadium/youtube-comments",
"headers": {
"Authorization": "Bearer <APIFY_TOKEN>"
}
}
}
}Then ask, for example:
Use arcadium/youtube-comments to read the 200 top comments of https://www.youtube.com/watch?v=dQw4w9WgXcQ and group them into the main topics, with the most liked comment for each topic.
More clients and the local setup on the MCP page.
Only recent comments, every week
For feedback under review videos, set "sortCommentsBy": "NEWEST_FIRST" and "oldestCommentDate": "7 days", save it as a Task and schedule it weekly. With newest-first order the actor stops reading a video at the first older comments. YouTube shows dates as "3 weeks ago", so the cut is approximate.
{
"urls": [
"https://youtu.be/dQw4w9WgXcQ"
],
"sortCommentsBy": "NEWEST_FIRST",
"oldestCommentDate": "7 days",
"maxComments": 500
}
Sentiment and topics
The text field is ready for analysis: emails, phone numbers and profile links are replaced and @mentions become @user. Use likeCount as a weight so the comments many viewers agree with count more, and isByChannelOwner to separate the creator’s own answers.
Output fields
Every row has a rowType; filter on it first. Failed inputs come back as free rows with a code and message. The fields this tutorial uses, from the actor’s dataset schema:
| Field | What it holds |
|---|---|
rowType | Kind of row. Filter on this first. Values: 'comment': one comment or reply (charged). 'error': a video gave no comments; see code and message (free). |
videoId | Video id, 11 characters. |
videoTitle | Video title. |
commentId | YouTube comment id, stable; replies are <parent id>.<reply id>. |
text | Comment text. Emails, phone numbers, profile links and @mentions of other users (replaced with @user) are removed. |
likeCount | Likes, rounded by YouTube above 1,000 (106K -> 106000). |
replyCount | Number of replies (top-level comments); 0 for replies. |
publishDate | Approximate date YYYY-MM-DD derived from publishedText (to the unit shown). |
isReply | True for a reply. |
parentCommentId | Replies: id of the comment replied to; null for top-level comments. |
isPinned | Pinned by the creator to the top. |
isHearted | The creator gave the comment a heart. |
isByChannelOwner | Written by the video's own channel. |
All fields: YouTube Comments Scraper guide.
Cost per run
Pay per event: you pay for the rows delivered, at the actor’s live Apify price on 2026-11-02. Error, coverage and summary rows are free.
| What | Rows | Price per row (Free plan) | Subtotal |
|---|---|---|---|
| Comment: 3 videos x 300 comments and replies | 900 | $0.0018 | $1.62 |
Cost of this example on the Apify Free plan: 900 × $0.0018 = $1.62 ($0.729 on the Apify Gold plan and higher), plus $0.001 per GB of memory when the run starts. Higher Apify plans pay less per row. The Store page always has the current price.
Limitations
- Videos with comments turned off and private or removed videos come back as free error rows that say why.
maxCommentscounts comments and replies together, so with replies on fewer top-level comments fit under the same cap.- YouTube shows comment dates as "3 weeks ago", so
publishDateand theoldestCommentDatecut are approximate (to the unit shown). - Like counts above 1,000 are rounded by YouTube ("106K").
- No author names, handles, avatars or author channels, by design. Old replies may start with the replied-to person's display name as plain text without an @; those are not always caught.
- Comments are read as an anonymous visitor sees them; held-for-review and members-only comments are not visible.
Links
- YouTube Comments Scraper: fields, price table and sample output
- How to use YouTube Comments Scraper: every input field, n8n, LangChain
- arcadium/youtube-comments on the Apify Store
- All tutorials