YouTube Comments Scraper avatar

YouTube Comments Scraper

Pricing

from $2.00 / 1,000 results

Go to Apify Store
YouTube Comments Scraper

YouTube Comments Scraper

Scrape the comments of one or MANY YouTube videos in a single run. Returns text, author, likes, thread structure (parent/depth) and the source video itself. Top or newest-first order, optional replies. No login, no API quota.

Pricing

from $2.00 / 1,000 results

Rating

0.0

(0)

Developer

code craker

code craker

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

Share

Apify actor that scrapes the comments of one or many YouTube videos in a single run and exports them as structured data — no login, no cookies, no YouTube API quota.

It reads the entry token from the video's watch page and pages through YouTube's own InnerTube /youtubei/v1/next API (the same requests the site itself makes). Requests go over plain HTTP first (fast and cheap); if YouTube blocks that, the actor automatically escalates to a real Chrome browser for the rest of the run — API requests then run inside the page as same-origin fetches.

Features

  • Batched: pass many video URLs and they are all scraped in ONE actor run (maxComments applies per video). Results are pushed after each video, so an abort or timeout keeps everything collected so far.
  • Any video reference works: youtube.com/watch?v=..., youtu.be/... short links, /shorts/... links, or a bare 11-character video id.
  • top (YouTube's ranked order) or newest first.
  • Replies included with full thread structure (parentCommentId + depth), or top-level comments only (includeReplies: false). Top-level comments are collected first; replies fill the remaining budget.
  • The source video itself is emitted too (flagged is_source_post: true) with title, channel, views, exact publish date and total comment count; disable with includeSourcePost: false. Videos with disabled comments are flagged (commentsDisabled: true) instead of failing.
  • Automatic block recovery: fresh proxy IP on each retry, plain HTTP → real Chrome escalation, EU consent interstitial bypassed via cookies.
  • When a run ends with 0 results, the last page fetched is saved as DEBUG_HTML in the run's key-value store.

Input

{
"urls": [
"https://www.youtube.com/watch?v=XXaUd0fGpOs",
"https://youtu.be/SSE4M0gcmvE"
],
"maxComments": 100,
"commentsSort": "top",
"includeReplies": true,
"includeSourcePost": true,
"proxyConfiguration": {
"useApifyProxy": true,
"apifyProxyGroups": ["RESIDENTIAL"],
"apifyProxyCountry": "US"
}
}

startUrls ([{ "url": ... }]) is accepted as an alternative to urls and merged with it. resultsLimit is accepted as an alias for maxComments.

Output

One dataset item per comment. Every item carries postId / postUrl / inputUrl, so comments from a multi-video run can always be attributed back to their source video.

{
"id": "Ugw4obgfNOpuN6L96qF4AaABAg",
"url": "https://www.youtube.com/watch?v=XXaUd0fGpOs&lc=Ugw4obgfNOpuN6L96qF4AaABAg",
"text": "Full text of the comment...",
"author": "@some_user",
"authorChannelId": "UCQLsJdT08EKD_7boRxYusGw",
"authorProfileUrl": "https://www.youtube.com/channel/UCQLsJdT08EKD_7boRxYusGw",
"authorAvatar": "https://yt3.ggpht.com/...",
"isCreator": false,
"isVerified": false,
"likeCount": 52,
"repliesCount": 3,
"edited": false,
"parentCommentId": null,
"depth": 0,
"publishedTimeText": "14 hours ago",
"created_at": "2026-07-08T18:53:19.009Z",
"postId": "XXaUd0fGpOs",
"postUrl": "https://www.youtube.com/watch?v=XXaUd0fGpOs",
"inputUrl": "https://www.youtube.com/watch?v=XXaUd0fGpOs",
"commentsSort": "top",
"is_source_post": false
}
  • parentCommentId is null for a top-level comment; otherwise the id of the comment it replies to (YouTube threads are exactly two levels deep). A reply's own id is parentId.replyId.
  • created_at is APPROXIMATE: YouTube only exposes relative publish times for comments ("2 weeks ago"); the raw value is kept in publishedTimeText.
  • isCreator marks the video's own channel commenting (YouTube's Creator badge) — the equivalent of Reddit's isSubmitter/OP.
  • The source video item has is_source_post: true with title, description, channelName, viewCount, numComments and an EXACT created_at (watch pages expose the real publish date).

Integration (scraping-tool)

Batched, like the other comment scrapers in scrapeCommentsForPostsBatched. Add a branch to scrapingService.scrapeCommentsBatch:

} else if (actor === 'outspoken_strategy/youtube-comments-scraper') {
delete input.startUrls;
input.urls = urls;
input.maxComments = cappedComments(input.maxComments ?? resultsLimit);
input.includeSourcePost = input.includeSourcePost ?? false;
input.includeReplies = input.includeReplies ?? false; // match FB: top-level only
input.proxyConfiguration = input.proxyConfiguration ?? { useApifyProxy: true, apifyProxyGroups: ['RESIDENTIAL'], apifyProxyCountry: 'US' };
}

Attribution in _matchCommentToPost (platform youtube): match on item.postUrl, item.inputUrl or item.postId — a good _postMatchKey is the video id extracted with /[?&]v=([A-Za-z0-9_-]{11})/ (plus the youtu.be/shorts variants).

Normalization hints: likesCountlikeCount, repliesCount is already named, createdTimecreated_at (approximate), parentCommentId is already named, and author fields are flat (author, authorChannelId, authorProfileUrl).

Local development

npm install
echo '{ "urls": ["https://www.youtube.com/watch?v=XXaUd0fGpOs"], "maxComments": 25, "proxyConfiguration": { "useApifyProxy": false } }' > storage/key_value_stores/default/INPUT.json
npm start

Deploy with apify push.