YouTube Comments Scraper — Comments & Replies avatar

YouTube Comments Scraper — Comments & Replies

Pricing

from $0.30 / 1,000 results

Go to Apify Store
YouTube Comments Scraper — Comments & Replies

YouTube Comments Scraper — Comments & Replies

Comments Scraper extracts comments, replies, likes and author details from any YouTube video URL or ID — no YouTube Data API key or quota needed.

Pricing

from $0.30 / 1,000 results

Rating

0.0

(0)

Developer

Murat Uzun

Murat Uzun

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

a day ago

Last modified

Features

Limited permissions

Share

What is YouTube Comments Scraper?

Recorded price: $0.0005 per accepted comment or reply ($0.50 per 1,000) on the Free plan, plus $0.00005 per run. Source: November 4, 2026 pricing readback recorded below; confirm current plan rates in the Pricing tab before running. Diagnostics are not billable comment rows.

YouTube Comments Scraper extracts comments, replies, likes, and author details from any public YouTube video — no YouTube Data API key, no daily quota, and no browser required. Paste a video URL or ID and get one structured row per comment: text, author, like count, reply count, pinned/hearted flags, and an approximate publish date. Point it at any YouTube video and run it on Apify with scheduling, API access, and webhook integrations built in.

Under the hood it talks directly to YouTube's own youtubei/v1/next endpoint — the same JSON API the youtube.com website itself uses to load comments — so there's nothing to authenticate and no per-request cost from Google.

Why use YouTube Comments Scraper?

  • Sentiment and brand monitoring — sample available comments on a product review or ad campaign video to gauge audience reaction without opening YouTube.
  • Keyword monitoring that only charges for matches — enter your brand, product or competitor names in Only comments containing and get just the comments that mention them; the Actor scans the rest for free, so you don't pay for thousands of unrelated comments.
  • Creator research — see what an audience actually says about a channel's videos before a sponsorship or collab deal.
  • Lead generation — commenters who ask questions about a product or service under a competitor's video are warm leads; export their channel names and profile links.
  • Community management at scale — export pinned/hearted comments and top replies for a weekly highlights digest.

How to use YouTube Comments Scraper

  1. Click Try for free (or Run if you already have it open).
  2. In Videos, paste one or more YouTube URLs or bare video IDs.
  3. Set Max comments per video, choose whether to include replies, and pick a sort order (Top or Newest).
  4. Click Start and watch rows appear in the Dataset tab as they're scraped.
  5. Export the results as JSON, CSV, Excel, or HTML, or pull them via the API.

Input

FieldTypeDescription
videosarrayVideo IDs or URLs (watch, shorts, youtu.be). Default: ["dQw4w9WgXcQ"].
proxyConfigurationobjectApify Proxy settings — required for platform runs, see Proxy requirement below. Default: Residential proxy.
maxCommentsPerVideointegerCap per video, 1–10,000. Default 100.
includeRepliesbooleanAlso fetch replies (counts toward the cap). Default false.
sortByenumtop or newest. Default top.
maxConcurrencyintegerVideos scraped in parallel, 1–10. Default 3.
languagestringUI language code for relative-time text. Default en.
keywords, keywordMatcharray, enumOptional: only comments containing these words/phrases (any or all) are output and charged; rows list matchedKeywords.
oldestCommentDatestringOptional: only comments on or after a date (2026-03-01) or within an age (7 days). Forces newest-first.
maxScannedCommentsPerVideointegerFilter mode only: comments read per video while looking for matches, 1–5,000. Default 1000.

See the Input tab for the full schema with examples.

Example input

{
"videos": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ", "jNQXAC9IVRw"],
"maxCommentsPerVideo": 100,
"includeReplies": false,
"sortBy": "top"
}

Keyword and date filters: pay only for matching comments

Fill Only comments containing (keywords) to turn the Actor into a mention monitor. It reads up to maxScannedCommentsPerVideo comments per video (and replies, if enabled), keeps only comments whose text contains a keyword, and adds a matchedKeywords field listing which ones matched. Only matching comments are pushed to the dataset, so only matches are charged; scanned comments that don't match cost nothing. Matching ignores upper/lower case and accents (cafe matches Café), collapses repeated spaces, and is a plain substring match, so apple also matches pineapple. Use keywordMatch: "all" to require every keyword in the same comment.

{
"videos": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
"keywords": ["never gonna", "rickroll"],
"maxCommentsPerVideo": 100,
"maxScannedCommentsPerVideo": 2000
}

maxCommentsPerVideo caps the matches you pay for; maxScannedCommentsPerVideo caps how far down the comment list the Actor looks. OUTPUT reports scannedComments, matchedComments, noMatchVideos and scanLimitedVideos. A video with no match adds a NO_KEYWORD_MATCH note to ERRORS; a video where the scan limit stopped the search adds FILTER_SCAN_LIMIT, so you know later comments were not checked. If nothing matched anywhere, the run still succeeds with zeroResultReason: "NO_KEYWORD_MATCH" in OUTPUT instead of failing.

Only recent comments: set oldestCommentDate to a date (2026-03-01) or an age (7 days, 2 weeks, 3 months, 1 year) to keep only comments published on or after it. The Actor switches to newest-first order and stops paging at the first older comment (an old pinned comment does not end the window), so a weekly monitoring run reads only the new part of the thread. Reply threads are opened only for comments inside the window. YouTube shows only relative times ("3 weeks ago"), so the cut-off uses publishedAtApprox and has YouTube's granularity: a comment shown as "1 month ago" counts as 30.4 days old. It combines with keywords (both must pass). An empty window succeeds with zeroResultReason: "NO_COMMENT_IN_DATE_RANGE". An unreadable value stops the run before any request, with a message saying which formats work.

Proxy requirement

YouTube can block comment requests from datacenter IPs. The input schema defaults to Apify Residential Proxy. For each video, the Actor creates one proxy session and reuses its connection across sequential comment and reply pages, then closes it. Parallel videos have separate sessions. A block or transport failure can rotate the session; a failed reused connection falls back to the existing one-shot proxy path, which can ultimately try a direct request. Proxy initialization failure also falls back to direct requests.

This is the recorded source behavior, not a guarantee of access. Proxy group availability and cost depend on the account and platform configuration; neither Residential nor datacenter access is guaranteed to bypass YouTube restrictions.

Output

One row per accepted comment (or reply when includeReplies is on). This illustrative excerpt uses captured fixture values, not a fresh live result; the full schema includes additional author/channel fields:

{
"videoId": "dQw4w9WgXcQ",
"videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"videoTitle": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
"channelName": "Rick Astley",
"commentId": "Ugzge340dBgB75hWBm54AaABAg",
"parentCommentId": null,
"isReply": false,
"text": "can confirm: he never gave us up",
"author": "@YouTube",
"authorChannelId": "UCBR8-60-B28hp2BmDPdntcQ",
"authorIsVerified": true,
"likeCount": 314000,
"replyCount": 963,
"publishedTimeText": "1 year ago",
"publishedAtApprox": "2025-09-12T00:00:00.000Z",
"isPinned": true,
"isHearted": true,
"scrapedAt": "2026-09-12T00:00:00.000Z",
"error": null,
"errorCode": null
}

You can download the dataset in various formats such as JSON, CSV, Excel, or HTML.

Data table

FieldDescription
videoId, videoUrl, videoTitleThe video the comment belongs to
channelName, channelIdThe video's uploading channel
commentId, parentCommentId, isReplyComment identity and threading
text, author, authorChannelId, authorUrl, authorAvatarComment content and author
authorIsVerified, authorIsCreatorAuthor badges
likeCount, replyCountEngagement counts
publishedTimeText, publishedAtApproxWhen it was posted (exact text + approximate ISO date)
isPinned, isHeartedCreator moderation signals
error, errorCodeNull on comment rows; failures use the ERRORS key-value record

Pricing

This Actor uses Pay-per-event pricing: $0.0005 per comment row on the Free plan ($0.50 per 1,000 rows). Per 1,000 rows, the other plan rates are Starter $0.40, Scale $0.35, and Business $0.30. Every plan also has an Actor Start event of $0.00005 per run, charged once per run, not per video or comment. Scraping 100 comments from each of 10 videos in a single run (1,000 rows) on the Free plan costs $0.50 + $0.00005 = $0.50005. These rates reflect the November 4, 2026 pricing readback; see the live Pricing tab for current plan-specific rates. There is no separate compute-unit charge on top — the price already covers it.

The source checks capacity against apify-default-dataset-item and sends only accepted, usable comment rows to the dataset. ERRORS diagnostics are stored separately. Numeric event prices and the Actor Start fee are platform configuration, not constants in the scraper code. The historical readback above is not a new live billing measurement; proxy usage and plan allowances should be checked in your account rather than estimated from older test runs.

YouTube Comments Scraper vs. the YouTube Data API

The official YouTube Data API v3 commentThreads.list endpoint requires a Google Cloud project, an API key, and burns your daily quota (10,000 units — a few thousand comment reads) fast. This Actor reads the same public data YouTube's own website loads, with no key, no quota, and results delivered as a ready-to-export dataset instead of raw API pages you have to paginate yourself.

JavaScript, Python and CLI examples

These examples use the same small input and the Apify synchronous dataset endpoint. They start a real, potentially billable run when executed; they were not executed for this documentation update. Supply your own token through APIFY_TOKEN in your local environment. The response is dataset items only: use the run in Apify Console to inspect OUTPUT, ERRORS and terminal status, including when the dataset is empty. For larger jobs use asynchronous runs and retrieve the dataset after completion; do not blindly retry a timed-out synchronous request, since the original run may still exist.

Save this as input.json for the CLI example:

{
"videos": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
"maxCommentsPerVideo": 10,
"includeReplies": false,
"sortBy": "top",
"maxConcurrency": 1
}

JavaScript (Node.js with built-in fetch)

const response = await fetch(
'https://api.apify.com/v2/acts/webdatatools~youtube-comments-scraper/run-sync-get-dataset-items',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.APIFY_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
videos: ['https://www.youtube.com/watch?v=dQw4w9WgXcQ'],
maxCommentsPerVideo: 10,
includeReplies: false,
sortBy: 'top',
maxConcurrency: 1,
}),
},
);
if (!response.ok) throw new Error(`Run request returned HTTP ${response.status}`);
console.log(await response.json());

Python (standard library)

import json
import os
from urllib.request import Request, urlopen
request = Request(
'https://api.apify.com/v2/acts/webdatatools~youtube-comments-scraper/run-sync-get-dataset-items',
data=json.dumps({
'videos': ['https://www.youtube.com/watch?v=dQw4w9WgXcQ'],
'maxCommentsPerVideo': 10,
'includeReplies': False,
'sortBy': 'top',
'maxConcurrency': 1,
}).encode('utf-8'),
headers={
'Authorization': 'Bearer ' + os.environ['APIFY_TOKEN'],
'Content-Type': 'application/json',
},
method='POST',
)
with urlopen(request, timeout=300) as response:
print(json.load(response))

CLI (curl)

curl --fail-with-body --request POST \
'https://api.apify.com/v2/acts/webdatatools~youtube-comments-scraper/run-sync-get-dataset-items' \
--header "Authorization: Bearer ${APIFY_TOKEN}" \
--header 'Content-Type: application/json' \
--data-binary @input.json

Using YouTube Comments Scraper with AI agents / MCP

In a client connected to the Apify MCP Server, select or discover webdatatools/youtube-comments-scraper. Tool availability depends on the client's Apify connection and enabled tools. Example request:

Run webdatatools/youtube-comments-scraper for https://www.youtube.com/watch?v=dQw4w9WgXcQ with maxCommentsPerVideo 10, includeReplies false, sortBy top and maxConcurrency 1. Report the returned comments and check OUTPUT and ERRORS for empty or partial results. Do not describe a capped export as the video's complete comment history.

This is a client prompt example, not a claim that an MCP run or live acceptance has been performed.

FAQ

Do I pay for comments that don't match my keywords or date window? No. With keywords or oldestCommentDate set, only matching comments become dataset rows, and you are charged per dataset row (plus the per-run start fee). Non-matching comments are read and discarded. Scanning is bounded by maxScannedCommentsPerVideo (max 5,000 per video), and OUTPUT tells you how many comments were scanned versus matched.

What does a small run cost? At the recorded Free-plan rate, 10 accepted comment/reply rows cost $0.005 plus the $0.00005 start event, or $0.00505 in listed events. This is an arithmetic example, not a measured invoice or proxy-cost estimate. Confirm current rates in the Pricing tab.

Do failed pages, empty results or replies cost extra? Replies count as comment rows and share maxCommentsPerVideo. Diagnostics and rejected duplicate rows are not sent to the billable dataset. A run with zero accepted comments can still incur its start event; zero results do not mean zero total cost. Check OUTPUT, ERRORS and the run's charge details together.

Is this legal? The Actor reads publicly visible comments the same way a browser loading youtube.com does. Respect YouTube's Terms of Service and applicable data-protection law for how you store and use the results.

Why is publishedAtApprox approximate? YouTube never sends an exact comment timestamp to the client — only relative text like "2 years ago". The date is computed by subtracting that duration from the scrape time, so treat it as a good estimate, not an exact value.

Will large batches get rate-limited? The Actor routes requests through Apify Proxy by default (see Proxy requirement above) — each parallel video gets one session reused across its comment and reply pages, with rotation on certain failures. For very large batches, keep maxConcurrency at 2–3; on an HTTP 429 the Actor waits 5 seconds and retries once before giving up on that page.

What about private, deleted, restricted videos or disabled comments? When comments cannot be read, the failure goes into ERRORS, outside the billable dataset. A run with no usable comments fails on invalid input or source failures; reached pages with no comments succeed; mixed runs retain usable comments. Start fees may still apply.

How do budgets and incomplete exports work? The Actor reserves comment capacity before fetching each video and passes that limit into pagination. Unused capacity is available to later videos. Tight budgets reduce concurrency. OUTPUT reports requested/attempted/skipped videos, budget-limited videos, delivered comments, diagnostic rows and partial output. Failed or repeated continuation pages retain collected comments and add an ERRORS diagnostic. Comment IDs are deduplicated within each video. An uncertain dataset write sets deliveryUnconfirmed, stops further work and is not retried automatically. These counters describe this process attempt, not guaranteed totals across migrations; capped or partial exports are not complete comment histories.

Can I use this in n8n, Make, or Zapier? Yes — call the Actor via its Apify API endpoint from any of these tools' native Apify integration or a generic HTTP node, or trigger it from a webhook.

Part of the webdatatools web-intelligence suite — every Actor is pay-per-event, reads public data without a login, and returns one clean row per entity:

Browse the whole suite at webdatatools, or call ten of these Actors straight from Claude, Cursor or Cline with the webdatatools MCP server.

Website & domain intelligence

Content for AI, LLMs and RAG

Search, video and social

Leads, jobs and company data

Developer, app and research data

Support

Found a bug or have a feature request? Open an issue on the Actor's Issues tab in Apify Console. Custom scraping solutions are also available on request.

Diagnostic codes and legacy error consumers

Accepted dataset comments retain all existing fields, including error: null, and add errorCode: null. Diagnostics are not dataset items and incur no dataset-item event. This is a compatibility change for integrations that previously filtered dataset rows by error: read the default key-value store's ERRORS record as well. Each diagnostic keeps all legacy row field names (unavailable values are null), error contains human-readable text, and errorCode is a stable machine-readable code. Input diagnostics also retain query. For a legacy combined export, concatenate dataset items and ERRORS locally; do not push diagnostics back into the billable dataset. Start fees may still apply.

errorCodeMeaning
INVALID_INPUTEmpty input or unrecognisable video URL/ID.
ACCESS_BLOCKEDSource returned HTTP 403 or 429 after retries.
RUN_TIMEOUTRun collection deadline reached; time reserved for saving diagnostics.
REQUEST_TIMEOUTSource request exhausted retries with a timeout/abort.
REQUEST_FAILEDOther HTTP, network or JSON response failure.
COMMENTS_UNAVAILABLESource reports disabled/unavailable comments.
NO_COMMENTSNo comments could be read; does not prove the video has none.
CONTINUATION_REPEATEDA continuation token repeated; export may be incomplete.
PAGINATION_STALLEDPagination yielded no new comments; export may be incomplete.
DUPLICATE_COMMENTRepeated comment ID was rejected within a video.
UNUSABLE_COMMENTA row lacks a comment ID or usable text.
DELIVERY_UNCONFIRMEDDataset write failed; delivery is uncertain and not retried.
NO_KEYWORD_MATCHFilter mode: no scanned comment contained the keywords (information, not a failure; nothing charged).
NO_COMMENT_IN_DATE_RANGEFilter mode: no comment inside oldestCommentDate (information, not a failure).
FILTER_SCAN_LIMITFilter mode: maxScannedCommentsPerVideo stopped the search; later comments were not checked.
INTERNAL_ERRORUnexpected processing failure.

OUTPUT.status and the terminal status message distinguish SUCCEEDED, PARTIAL, NO_RESULTS and FAILED. Access blocks use FAILED with ACCESS_BLOCKED diagnostics. OUTPUT.statusMessage includes accepted count, rejected diagnostic count and codes, skipped video count, and limit reasons. rejectedRows counts diagnostic records, not missing comments or failed videos; rejectionReasons groups those records by code. One failed page is one diagnostic even when the number of missing comments is unknown. Existing summary counters remain. limitReasons identifies BUDGET_LIMIT or RUN_STOPPED; zero budget is NO_RESULTS with skipped videos and no source requests. Mixed results remain available as PARTIAL. Reached pages diagnosed only as NO_COMMENTS or COMMENTS_UNAVAILABLE succeed with zero accepted comments; their diagnostic counts and reasons remain visible. Zero-result batches containing invalid input or source failures fail the Actor. NO_RESULTS is reserved for no-attempt results such as zero budget. ERRORS is written even when empty. The Output tab links both records. These are process-attempt counts, not migration totals.

Run deadline and diagnostic shutdown

The Actor logs its effective timeoutAt and its source. It uses the run environment's timeoutAt when available; otherwise it uses .actor/actor.json's defaultRunOptions.timeoutSecs (3600 seconds), measured from environment startedAt when available or process orchestration start. This fallback cannot detect a shorter platform override when the environment omits its deadline.

Collection stops 10 seconds before that deadline, reserving time for ERRORS, OUTPUT and the terminal message. OUTPUT adds timeoutAt, timeoutSource, shutdownReserveMs and timedOut; RUN_TIMEOUT appears in diagnostics and limit reasons. Delivered comments remain available as PARTIAL; a timeout with no delivered comments is FAILED. Reached empty pages and invalid/access-blocked inputs retain their documented behavior. Only accepted comment rows use the existing dataset-item event.

Each closing write gets a share of the remaining time, retaining one second for exit. A failed or hanging closing write does not prevent attempts at subsequent writes, but causes the run to fail rather than claiming that finalization succeeded. Remote writes cannot be recalled: a dataset write that exceeds the collection deadline is marked deliveryUnconfirmed, is not counted as confirmed delivery and is never retried. If the platform deadline has already passed, persistence cannot be guaranteed.

If you have used this Actor, please leave an honest review on its Apify Store page.