YouTube Video Comment & Reply Thread Scraper avatar

YouTube Video Comment & Reply Thread Scraper

Pricing

from $0.49 / 1,000 results

Go to Apify Store
YouTube Video Comment & Reply Thread Scraper

YouTube Video Comment & Reply Thread Scraper

Get a YouTube video's comments with nested replies attached, author identity, like counts, and pinned/hearted/verified flags, filterable by keyword and minimum likes.

Pricing

from $0.49 / 1,000 results

Rating

0.0

(0)

Developer

Nimbryxo-studio

Nimbryxo-studio

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

19 days ago

Last modified

Features

Limited permissions

Share

Scrape YouTube comments and reply threads as analysis-ready rows. Give it video links, channel video tabs, playlists, or search queries, and get one row per comment or reply with author identity, engagement signals, thread position, and video context. Works on public videos without user cookies, login, or an API key.

What this actor does

  • Four source types: individual videos (watch, Shorts, live, embed, youtu.be, bare ID), channel video tabs, playlists, and video search results
  • Flat rows by default: every comment and reply is its own row with parentCommentId, rootCommentId, replyLevel, and threadPosition, so CSV, Excel, SQL, and sentiment pipelines can use it directly
  • Full reply threads: fetch every page of a thread, cap per comment, or skip replies entirely; maxRepliesPerComment: 0 means all
  • Real filters: Top/Newest sort, date cutoff, multiple keywords (ANY match), minimum likes, and only creator-hearted comments
  • Honest engagement data: rounded like counts with the original text, advertised reply counts, pinned/hearted/verified flags, and approximate dates with a precision and range
  • Video context on every row: title, channel, views, likes, comment count, duration, publish date, and description
  • Empty fields are omitted — records only contain values that are actually populated.

Output per comment or reply

Each dataset row is one comment (recordType: "comment", replyLevel: 0) or one reply (recordType: "reply", replyLevel: 1).

FieldTypeDescription
recordTypestringcomment, reply, or status
commentIdstringYouTube comment identifier
parentCommentIdstringRoot comment ID on replies; omitted on top-level comments
rootCommentIdstringThread root ID (own ID on top-level comments)
replyLevelinteger0 for comments, 1 for direct replies
threadPositioninteger1-based order in the emitted feed or reply thread
isReplybooleanBackward-compatible alias for replyLevel > 0
replyDepthintegerBackward-compatible alias for replyLevel
textstringComment text, with unicode and newlines preserved
authorNamestringDisplay name
authorHandlestring@handle when YouTube exposes it
authorChannelIdstringUC... channel ID
authorChannelUrlstringhttps://www.youtube.com/@handle or /channel/UC...
authorAvatarUrlstringAvatar image URL
authorIsVerifiedbooleanAuthor channel is verified
authorIsCreatorbooleanAuthor is the video's channel owner
authorIsArtistbooleanAuthor is marked as a YouTube Music artist
likeCountintegerRounded like count (69K becomes 69000)
likeCountTextstringOriginal formatted count (69K)
replyCountintegerYouTube's advertised reply count; may exceed visible replies
replyCountTextstringOriginal reply-count text when YouTube exposes it (963 replies)
repliesFetchedintegerReply rows actually attached/emitted for this comment (present when replies were fetched)
isPinnedbooleanComment is pinned
pinnedByTextstringPinned-by tooltip (Pinned by @channel)
isHeartedbooleanCreator hearted the comment
heartedBystringCreator handle from the heart tooltip
heartedByTextstringNormalized creator label for the heart
creatorRepliedbooleanWhether any emitted reply is authored by the video creator (present when replies were fetched)
creatorReplyCountintegerNumber of emitted replies authored by the creator (present when replies were fetched)
isEditedbooleanComment was edited, derived from the (edited) label
publishedTimeTextstringRelative publish text exactly as YouTube shows it
publishedAtApproxstringMidpoint of the inferred date range (ISO-8601)
publishedAtFromstringEarliest possible publish time
publishedAtTostringLatest possible publish time
publishedAtPrecisionstringsecond, minute, hour, day, week, month, or year
ageDaysMinnumberLower bound of comment age in days
ageDaysMaxnumberUpper bound of comment age in days
ageDaysApproxnumberMidpoint of the age range
commentUrlstringDirect link to the comment (...&lc=COMMENT_ID)
videoIdstringVideo ID
videoUrlstringCanonical watch URL
videoTitlestringVideo title
videoChannelIdstringVideo channel ID
videoChannelHandlestringVideo channel path (/@handle)
videoChannelNamestringVideo channel display name
videoViewCountintegerView count
videoLikeCountintegerVideo like count (YouTube may round it)
videoCommentCountintegerApproximate total comments shown by YouTube
videoPublishDatestringRaw publish date text (Oct 24, 2009)
videoPublishedAtstringParsed publish date (2009-10-24)
videoDurationSecondsintegerVideo length in seconds
videoDescriptionstringVideo description
sourceInputstringThe original URL, handle, or query that produced this video
sourceScopestringvideo, channel, playlist, or search
sourceVideoIdstringVideo selected from the source
scrapedAtstringISO-8601 UTC timestamp of the run
repliesarrayEmbedded reply rows, only with outputMode: tree or both

Status rows

When emitStatusRows is enabled, blocked/empty/unavailable sources and partial or budget-limited runs add one row with recordType: "status", status, inputUrl, optional video fields, error, and rowsEmitted when known. Status rows are never counted toward maxTotalRows and do not consume the data-row budget. Status values: no_comments, comments_off, unavailable, private, age_restricted, members_only, region_blocked, live_chat_only, blocked, stale_token, transient_empty, parse_empty, partial, budget_reached, input_invalid. Successful comment runs do not add an ok status row.

Dates and counts are approximate

YouTube's public comment payload does not expose exact timestamps. Every date field is derived from the relative label (6 years ago) and comes with a precision plus earliest/latest bounds, so no exact timestamp is invented. Like counts above 999 are rounded by YouTube itself; likeCountText preserves the original value. replyCount is YouTube's advertised count and can be higher than the number of replies the public thread returns.

Input

FieldTypeDefaultDescription
videoUrlsarray[]Video URLs or bare IDs (watch, youtu.be, Shorts, embed, live, v/)
channelUrlsarray[]Channel video tabs: /@handle, /channel/UC..., /c/name, /user/name, @handle, or UC...
playlistUrlsarray[]Playlist URLs or bare playlist IDs
searchQueriesarray[]Search terms or YouTube search-result URLs; video results only
maxVideosPerSourceinteger20Video discovery cap per channel/playlist/search; 0 = all
maxCommentsinteger100Top-level comments to examine per video; 0 = all. Filtered-out comments still count toward this scan cap
includeRepliesbooleantrueFetch reply threads
maxRepliesPerCommentinteger50Replies per thread; 0 = all until the token is exhausted
maxReplyDepthinteger10 = top-level only, 1 = direct replies
maxTotalRowsinteger5000Global comment + reply budget; 0 = unlimited
sortBystringtoptop or newest
commentsSincestring–ISO date/datetime or relative duration (7d, 24h); forces newest
keywordsarray[]Case-insensitive ANY-match filter on comment/reply text
minLikesinteger0Drop rows below this rounded like count
onlyCreatorHeartedbooleanfalseKeep only creator-hearted rows
outputModestringflatflat, tree, or both
emitStatusRowsbooleantrueEmit recordType: "status" rows for blocked/empty/invalid sources

At least one of videoUrls, channelUrls, playlistUrls, or searchQueries is required.

Example: one video with replies

{
"videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
"maxComments": 50,
"includeReplies": true,
"maxRepliesPerComment": 20,
"sortBy": "top",
"maxTotalRows": 500
}

Example: recent comments from a channel

{
"channelUrls": ["https://www.youtube.com/@RickAstleyYT"],
"maxVideosPerSource": 10,
"sortBy": "newest",
"commentsSince": "7d",
"maxComments": 100,
"minLikes": 5,
"maxTotalRows": 1000
}

Example: search with creator-hearted comments

{
"searchQueries": ["product launch review"],
"maxVideosPerSource": 5,
"onlyCreatorHearted": true,
"maxRepliesPerComment": 0,
"maxTotalRows": 2000
}

Example: backward-compatible tree output

{
"videoUrls": ["https://www.youtube.com/watch?v=jNQXAC9IVRw"],
"maxComments": 20,
"includeReplies": true,
"maxRepliesPerComment": 50,
"outputMode": "tree"
}

Use cases

  • Sentiment and topic analysis — export flat comment and reply rows directly into a notebook or BI tool
  • Creator engagement audits — measure which comments the creator pinned, hearted, or replied to
  • Audience research — mine questions and recurring themes across a channel's recent uploads or a playlist
  • Moderation datasets — collect long reply threads with parent/root IDs for context-aware classifiers
  • Campaign monitoring — pull the last few days of comments from several videos with a date cutoff and minimum-like floor
  • Competitive research — compare comment volume and engagement on the same topic across search results

FAQ

Do I need a YouTube API key or cookies?

No. The actor reads publicly available comment data without login, user cookies, or an API key. It sends YouTube's standard consent cookie so the EU consent page does not replace the video page.

Why are some comments missing?

YouTube's "Top comments" feed exposes a relevance-ordered subset (roughly 800–1,200 comments on very large videos). Use sortBy: "newest" for complete date windows and deeper coverage. The actor also continues with the newest feed when the top feed is exhausted, and maxComments, maxTotalRows, and your filters can all stop a run earlier than the source total.

Are replies complete?

The actor follows every reply continuation until the thread token is exhausted when maxRepliesPerComment: 0. YouTube can hide deleted, spam, or moderated replies, so the advertised replyCount may be higher than the rows returned. repliesFetched tells you exactly how many were emitted for a comment.

Why are timestamps approximate?

The public comment payload only contains relative labels such as "2 days ago". The actor converts each label into a date range with a precision (hour, day, week, month, year) and exposes the earliest and latest possible time. It never claims an exact timestamp.

Why do like counts end in round numbers?

YouTube exposes formatted counts (1.2K, 69K, 4.8M). likeCount is the rounded integer and likeCountText preserves the original string.

What does a date cutoff do?

commentsSince forces the newest-first feed, keeps pinned comments, and stops paginating at the first non-pinned comment older than the cutoff. Because dates are approximate, a comment whose range overlaps the cutoff is kept.

What happens if a video is private, age-restricted, or has comments off?

The actor classifies the page and, when emitStatusRows is enabled, writes one status row explaining the outcome. It does not try to bypass login, age, or region restrictions.

What is the difference between flat, tree, and both?

flat emits one row per comment and reply. tree emits parent comment rows with a replies[] array (useful for older integrations). both emits flat reply rows and also attaches replies[] to each parent.

Do I need to configure a proxy?

No. The actor chooses a working connection to YouTube automatically. Just fill in the input and run it.

Is this affiliated with YouTube?

No. This is an independent tool and is not affiliated with, endorsed by, or sponsored by YouTube or Google.

Limitations

  • Exact comment timestamps and exact like counts are not available in the public payload.
  • Nested replies beyond direct level 1 are not exposed in the observed public payload; maxReplyDepth above 1 is reserved for future support.
  • The top-comments feed is capped by YouTube; use newest-first plus a date cutoff for exhaustive windows.
  • Age-restricted, private, members-only, and region-blocked videos are reported as statuses, not bypassed.
  • replyCount is advertised, not guaranteed; use repliesFetched for the delivered count.