Monitor the Newest Comments on Your YouTube Videos Every Day
Read the newest comments on your YouTube videos every day with YouTube Comments Scraper, keep only unseen ones, and flag questions you have not answered.
The actor referenced in this article. Pay only for results delivered.
The first days after a video goes up are when an unanswered question costs the most: the viewer who asked is still around, and others are reading the thread. Checking by hand works on a quiet week. It breaks down with several videos, several people answering, or videos on channels you do not own, such as a partner’s launch, and it leaves no log of what was already seen.
Try it live: YouTube Comments Scraper: Comments and Replies, No Login. Pay per result delivered. Failed and empty results are never charged.
This guide sets up a daily run of the YouTube Comments Scraper on your latest videos, keeps only comments you have not seen, and flags questions your channel has not replied to yet.
What you get and who it is for
Each row is one comment or reply. For monitoring, these fields do the work:
| Field | Used for |
|---|---|
comment_id | The dedupe key; it does not change between runs |
text | Finding questions and complaints |
published_time_text, published_at | How old the comment is |
reply_count | Replies YouTube says the comment has |
is_reply, parent_comment_id | Linking replies to the comment they answer |
author_is_channel_owner | Your channel wrote this row |
is_hearted | Your channel hearted the comment |
comment_url | Opens the video with the comment highlighted, ready to answer |
It suits creators and their community managers, brands that post product and launch videos, and agencies watching several client channels from one script.
The input
{
"videos": [
"https://www.youtube.com/watch?v=VIDEO_ID_1",
"https://www.youtube.com/shorts/VIDEO_ID_2",
"VIDEO_ID_3"
],
"maxComments": 100,
"sortBy": "newest",
"includeReplies": true,
"maxRepliesPerComment": 10
}
- Replace the placeholders with your own videos. Watch links, Shorts links and bare 11 character ids all work, mixed in one list, and five videos are read at a time.
sortByset tonewestputs the most recent comments first, which is the order a monitor needs.maxCommentsis per video and counts replies too. Set it a little above what a video collects in a day.includeReplieswithmaxRepliesPerCommentat 10 reads up to 10 replies under each comment, which YouTube serves in one request, so the script can check whether your channel already answered.
What the output looks like
Two rows, trimmed, from our run on Rick Astley’s Never Gonna Give You Up video on October 7, 2026. That run used Top order, so sort_by reads top; a Newest run returns the same fields with sort_by set to newest. Commenter handles are masked and their channel fields dropped.
[
{
"video_id": "dQw4w9WgXcQ",
"video_channel_name": "Rick Astley",
"comment_id": "UgyXbabT1C58g-F4AGt4AaABAg",
"comment_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ&lc=UgyXbabT1C58g-F4AGt4AaABAg",
"text": "Forgot I was here. I rickrolled myself",
"author_name": "@S***************",
"author_is_channel_owner": false,
"likes": 2,
"reply_count": 0,
"is_hearted": false,
"is_reply": false,
"published_time_text": "9 hours ago",
"published_at": "2026-10-07T02:11:30.100Z",
"position": 49,
"sort_by": "top",
"scraped_at": "2026-10-07T11:11:30.100Z"
},
{
"video_id": "dQw4w9WgXcQ",
"comment_id": "Ugy0K3HrqLSgIwxXizl4AaABAg",
"text": "Fun fact is that the fans were so surprised that Rick was twenty one? And he had a voice of like a twenty nine year old",
"author_name": "@M***************",
"author_is_channel_owner": false,
"likes": 2,
"reply_count": 0,
"is_hearted": false,
"is_reply": false,
"published_time_text": "6 days ago",
"published_at": "2026-10-01T11:11:33.623Z",
"position": 91,
"sort_by": "top"
}
]
Even in Top order, 9 of the 100 rows in that run said “1 day ago” or less, and 19 had no replies at all. The first row shows how published_at is built: the scrape time minus 9 hours, so it is good to the hour. The second row is a warning about simple rules: it contains a question mark, yet it is a remark, not a question. On the same day we ran Me at the zoo, the first video ever uploaded to YouTube, and the uploader’s own comment came back with author_is_channel_owner set to true, the flag the script below relies on.
Run it in Apify Console
- Open https://apify.com/themineworks/youtube-comments-scraper and click Try for free.
- In YouTube videos or Shorts, paste your recent videos, one per line.
- Set Max comments per video to 100 and Sort comments by to Newest first.
- Switch on Include replies and set Max replies per comment to 10.
- Click Start and read the rows in the Output tab.
- Click Export to download CSV, JSON or Excel.
A Console export is fine for a one-off check. The daily job needs memory of what you have seen, which is what the script adds.
Run it from Python
pip install apify-client, then:
import csv
import json
from pathlib import Path
from apify_client import ApifyClient
SEEN_FILE = Path("seen_comment_ids.json")
seen = set(json.loads(SEEN_FILE.read_text())) if SEEN_FILE.exists() else set()
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("themineworks/youtube-comments-scraper").call(run_input={
"videos": [
"https://www.youtube.com/watch?v=VIDEO_ID_1",
"https://www.youtube.com/shorts/VIDEO_ID_2",
"VIDEO_ID_3",
],
"maxComments": 100,
"sortBy": "newest",
"includeReplies": True,
"maxRepliesPerComment": 10,
})
rows = []
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
if item.get("_type") == "status":
print("no comments:", item.get("input"), item.get("note")) # free row
continue
rows.append(item)
# threads your channel already replied to, and how many replies were read
answered, replies_read = set(), {}
for r in rows:
if r["is_reply"]:
parent = r["parent_comment_id"]
replies_read[parent] = replies_read.get(parent, 0) + 1
if r["author_is_channel_owner"]:
answered.add(parent)
new_rows = [r for r in rows if r["comment_id"] not in seen]
waiting = []
for r in rows:
if r["is_reply"] or r["author_is_channel_owner"] or "?" not in r["text"]:
continue
if r["comment_id"] in answered or r["is_hearted"]:
continue
all_read = r["reply_count"] <= replies_read.get(r["comment_id"], 0)
r["flag"] = "no reply from you" if all_read else "check: more replies than were read"
waiting.append(r)
fields = ["video_id", "comment_id", "is_reply", "text", "likes", "reply_count",
"published_time_text", "published_at", "comment_url", "flag"]
with open("new_comments.csv", "a", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=fields, extrasaction="ignore")
if f.tell() == 0:
writer.writeheader()
writer.writerows(new_rows)
with open("waiting_for_reply.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=fields, extrasaction="ignore")
writer.writeheader()
writer.writerows(waiting)
seen.update(r["comment_id"] for r in rows)
SEEN_FILE.write_text(json.dumps(sorted(seen)))
print(f"{len(new_rows)} new comments, {len(waiting)} questions waiting for a reply")
new_comments.csv grows by one day’s new comments per run. waiting_for_reply.csv is rebuilt each run from everything read that day: top comments with a question mark, not written by your channel, not hearted, and with no reply from your channel among the replies read. When a comment has more replies than were read, it is marked for a manual check rather than called unanswered, since your reply could sit further down the thread. Author handles stay out of both files.
Run it every morning
The dedupe file lives wherever the script runs, so the simplest setup is to run the script once a day from cron or any job runner, with a line such as 0 7 * * *. If you would rather keep the schedule in Apify, save the input as a task, open Schedules, create a schedule with the same cron expression and pick the task. Then add a webhook on a successful run that calls a small service of yours, which fetches the dataset and applies the same comment_id filter. The actor has no option to return only new comments, so that filter always runs on your side. From there, send the waiting list to Slack, a Google Sheet or email. If once a day is too slow during a launch, every six hours works for most channels. The same every-morning pattern works on review sites, where new Trustpilot reviews are picked up as they appear.
What it costs
$0.20 per 1,000 comment rows on the Bronze plan, and the same $0.20 on Silver, Gold and the higher plans, plus $0.005 per run. Five videos at 100 rows each, every day for 30 days: 15,000 rows, $3.00, plus 30 start fees of $0.005, $0.15. Rows you saw yesterday are charged again because they come back in the next run, so lowering maxComments to 50 on all five videos halves the row cost.
Limits worth knowing
- No memory between runs. Dedupe on
comment_idyourself, and expect to pay for the overlap. - If a video gets more comments between runs than
maxComments, the oldest of them fall outside the window and are never read. Run more often or raise the number. - A new reply under an older comment only shows up if that comment is inside the window you read.
published_atis as exact as YouTube’s relative text: minutes or hours for new comments, years for old ones.- The question mark rule is rough. It misses questions written without one and catches remarks like the second row above. Treat the waiting list as a queue to read, not a verdict.
Related
- Export a YouTube Video’s Comments and Replies to CSV, the companion guide for one full export
- YouTube Channel Scraper in Python, to pull your latest video links automatically
- Validating a business idea by mining reviews, the same read-the-complaints approach on review sites
- YouTube Comments Scraper on The Mine Works
Explore the scraper referenced in this article: inputs, outputs, and pricing, then run it on Apify.
Frequently asked questions
Does the actor remember which comments it already returned? +
No. Every run reads the newest comments again and charges for every row it returns. Store the comment_id values you have seen and drop them on your side, as the script in this guide does.
How exact is published_at on a new comment? +
It is the run time minus the relative age YouTube shows, so a comment marked 9 hours ago is placed to the hour and one marked 6 days ago to the day. For a daily monitor that is close enough to sort and filter on.
How many comments should I ask for each day? +
Set maxComments a little above the number of comments and replies a video gets between two runs. Too low and you miss comments; too high and you pay $0.0002 for each row you have already seen.
Does it work on Shorts? +
Yes. Shorts links and their ids go in the same videos list as regular videos, and the rows link back to the /shorts/ address.
How does the script tell that I already answered a comment? +
A reply written by your channel has author_is_channel_owner set to true, and a comment you hearted has is_hearted set to true. Either one takes the comment off the waiting list.
Export a YouTube Video's Comments and Replies to CSV
Pull a YouTube video's comments and their replies into one CSV with YouTube Comments Scraper, each thread rebuilt from parent_comment_id.
Monitor Competitor LinkedIn Company Posts on a Schedule
Get every new post from competitor LinkedIn company pages each day or week, with only-new mode and an Apify schedule. No LinkedIn login or cookies.
Track Competitor Instagram Reels Weekly With View Counts
Log every new reel your competitors post each week, with plays, likes and audio, using Instagram Reel Scraper on a weekly Apify schedule.
YouTube Channel Scraper: Subscribers, Video Stats and Channel Data Without a YouTube API Key
How to pull YouTube channel metadata and video lists: subscriber count, view counts, publish dates, video descriptions, without using the YouTube Data API or paying for quota.