# Changelog of YouTube Comments Scraper — Replies & New Comment Monitor (`foxlabs/youtube-comments-scraper`) Actor

- **URL**: https://apify.com/foxlabs/youtube-comments-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/foxlabs/youtube-comments-scraper.md

## Changelog

### 2026-10-08 — build 0.1.13

No input field changed, no output column changed, no pricing change.

- **The "wait for the next run" note counts the pinned comment.** A run of an "only new" list that could not deliver all of a video's new comments says how many wait. A video's pinned comment stands first whatever its age, and while it had not been delivered it was left out of that number: on the platform the note said 9 where the next run delivered 10 (runs `pud76wzTxqTl5ndnd` and `dyglEN1fs4G5gPhgh`, build 0.1.12). The number now includes it. What a run delivers, and in which order, did not change.

### 2026-10-08 — builds 0.1.9 to 0.1.12

Changes since the build that was published on 2026-10-07 (0.1.8). No input field changed, no output column changed, no pricing change. One order changed: the first run of an "only new" list that follows its videos (newest first, no filters) now writes a video's rows oldest first, as every later run already did.

- **A first look that one run cannot deliver whole is carried on (0.1.12).** An "only new" list started a video with a first look at its first `maxCommentsPerVideo` comments, and followed the video only once one run had delivered that look whole. With replies on — replies count as rows — or when the run stopped at `maxComments`, at a spending limit or at a timeout, the next run took the first look again, at the comments that were newest then: on a video that kept getting comments the older part was never delivered, and no message said so. An independent fact-check of the README found this; reproduced offline on recorded answers, 16 of the 30 comments that were due never came. The first look is now read whole and delivered oldest first, like every later run, and the list notes where it ends even when the run could not deliver all of it. The next runs go on from the delivered part upward, and the status message says how many comments wait. (A first look at more than 20,000 comments is still handed over newest first as it is read, and carried on only when one run delivers all of it.)

- An answer without a single comment for a video that counts 20 comments or fewer is no longer taken for a look at the video (0.1.12): for larger videos that was already so.

- `publishedDate` of a comment less than a day old is worked out from the moment the comment was read (0.1.12). It used the moment the row was made, which in a long reading — a list read whole before it is handed over — can be minutes later and, around midnight UTC, a day off.

- **Wording of a run's last word (0.1.12).** A run that delivers nothing used to say "nothing charged". The run-start event ($0.00005) is charged for every run, so the message now says "no rows charged". Nothing about charging itself changed.

- **README corrected after an independent fact-check (0.1.12):** 18 statements were wrong or said more than the measurements do, 10 had no record behind them. Among them: a burst is carried over only newest first and without filters — with a filter or in "top" order a run looks at a window and cannot tell what fell outside it; a thread longer than `maxRepliesPerComment` is read again in every run until it is exhausted; a comment that reaches YouTube's list late is found only within about a quarter of an hour of the list's last complete reading; a monitoring run took 4 to 12 seconds, not "4 to 5"; the three streams we saw on air showed no comment section. The full list is in the Actor's QA record.

- **"Only new comments" no longer loses the older part of a burst.** Newest first and without filters, a run used to deliver a video's newest new comments up to `maxCommentsPerVideo`; if more had been written between two runs, the older ones of them were never delivered. A run now delivers a video's new comments oldest first, so what does not fit into one run — or what `maxComments`, the spending limit or a timeout cuts off — is delivered by the next run, and the status message says how many comments are waiting. Within a video the rows of such a run now come oldest first (they came newest first).

- A list that was started with the published build goes on working: each video takes one more look at its first `maxCommentsPerVideo` comments (what was delivered is skipped) and is followed from then on.

- **A video without a comment section: the status row says why**, as the video's own page tells it — the page says "Comments are turned off", the video is for the channel's members only, or the video is private. It used to name the reasons there can be. The page is read for the first 25 such videos of a run.

- **A private video in the input no longer slows the run down.** YouTube's embed answer for a private video (HTTP 403) was taken for a refusal of the run's address: it was retried and moved the run's small requests to the proxy. It is now read as what it is.

- A video whose owner has turned embedding off now carries its channel's @handle too (`videoChannelHandle`), read from the video's page.

- A first page of comments that comes back without a comment is asked once more before it is believed, and an "only new" list no longer takes such an empty answer for a look at the video.

- The Actor's title in Apify Store is now "YouTube Comments Scraper — Replies & New Comment Monitor" (it was "YouTube Comments Scraper — New Comments, Replies, Exact Counts"). Its address `foxlabs/youtube-comments-scraper` is the same.

- README rebuilt in the foXLabs layout: use with AI agents (Apify MCP server, agentic payments), getting started, use cases, integration, legal notes.

- README, build 0.1.11 (no change in what the Actor does): the Python example reads the dataset as `run.default_dataset_id` — with the current Apify Python client (3.x) the `run['defaultDatasetId']` of the earlier example raises an error; the README's own examples were run as written; a comment list of 119,554 comments followed to its end is on record under *Data quality*; what a run with nothing new costs is stated as measured (one or two comment requests).

### 0.1 — first version (published 2026-10-07)

What the Actor does, as it stands with the changes above.

**What it reads**

- The comments of YouTube videos, given as video URLs or IDs (watch, youtu.be, Shorts and live addresses), in YouTube's own two orders, 20 comments a request.
- "Newest first" is the default: it lists every comment of a video. "Top comments" is YouTube's own selection, which for a video with thousands of comments holds only a part of them; when a list ends far below the number YouTube shows for the video, the run's status message says so, in either order. (A Top list runs out in empty pages; three in a row are taken as its end.)
- Channel lines: for each channel, the comments of its latest videos (`maxVideosPerChannel`; Videos, Shorts and Live lists). Videos for the channel's paying members are left out.
- Replies on request (`maxRepliesPerComment`): each comment is followed by its replies, oldest first — the only order YouTube gives them in.

**What a row holds**

- The comment's text, author (name, @handle, channel ID), like count (`likesAreRounded` when YouTube shows "25K"), reply count, the pin, the owner's heart, whether the author is the video's owner, a direct link to the comment — and the video, its channel and the number of comments YouTube shows for it, to the last digit.
- YouTube shows no date for a comment, only "3 weeks ago": the row carries that text and the range of days it can mean (`ageDaysMin`, `ageDaysMax` — for "1 month ago" and "2 years ago" bounds that hold whether YouTube counts 30-day or calendar months). `publishedDate` is given only for a comment less than a day old, and only when the hour YouTube names lies within one UTC day; otherwise it is `null`.
- A video named by its address is named from YouTube's public embed answer. A video whose owner has turned embedding off has no such answer: its own page names it and its channel, @handle included.

**Filters**

- `publishedWithinDays` (newest first, reading stops at the first comments that are certainly older), `minLikes`, `textContains`. Comments and replies are judged alike, each on its own.
- A run whose filters let almost nothing through stops reading and says which of its two limits it met: fewer than one comment in a hundred passed (judged after 5,000 comments), or 50 comments were read for each row of `maxComments` without filling it.
- A video that fills `maxCommentsPerVideo` before the date limit is named in the status message. A video whose comments were read and all removed by the filters gets a free status row of its own.

**"Only new comments" — a named list remembers what was delivered**

- Newest first and without filters, the list follows each video. The first run delivers a video's first comments up to `maxCommentsPerVideo`. Every later run reads from the newest comment down to where the delivered ones begin and delivers what is new, oldest first. Whatever ends a run early — the video's number, `maxComments`, the spending limit, a timeout — what is left is the newest part, and the next run delivers it: a burst of comments larger than one run's number arrives over the following runs instead of being skipped. The status message says how many new comments are waiting.
- With a filter or in "Top" order, every run looks at each video's first `maxCommentsPerVideo` comments and delivers what the list has not delivered. An input that looks at more comments in every run than a list remembers (150,000 entries) is refused before the run starts.
- With replies, a comment delivered before has its replies read again when YouTube shows another number of replies for it, or when not all of its replies were delivered: a thread longer than `maxRepliesPerComment` is read again in every run until it is exhausted.
- Interrupted runs: the rows a run wrote before the platform restarted it are taken into the list when the run continues. A run that is killed (a timeout, the memory limit) cannot save the last rows it delivered; the list's next run reads them back from that run's dataset before it starts. A write of the list that fails does not end the run: it is made up for with the next rows and at the end of the run, and if the list still cannot be saved the status message says so. A list that has reached its size says how many of its oldest entries it let go.
- `listName` takes letters, digits and hyphens (a hyphen not first or last, up to 40 characters; capitals are read as lower case). Any other name is refused before the run starts.

**When there is nothing to deliver**

- A video that shows no comment section gets a free status row that says why, as the video's own page tells it: comments are turned off (also on a stream that is on air or has not started), the video is for the channel's members only, or the video is private. The page is read for the first 25 such videos of a run; the rows of the others name the reasons there can be.
- A video without comments, a video YouTube does not know, a line that is not a video or channel, and a video or channel named twice each get a free status row that says so. A line that repeats another line letter for letter is read once and counted in the status message.
- An error answer from YouTube is reported as a failure, not as "no comments".
- A run that delivered nothing and wrote no status row writes one free row with its last word, so its dataset does not come back empty without a reason. An "only new" run that finds nothing new leaves the dataset empty and says so in its status message.

**Running and paying**

- Pay per delivered row with one event, `comment` (a comment or a reply). Status rows are free.
- A run the platform restarts continues from the rows it already delivered and does not repeat its status rows.
- No proxy to set up: requests go out directly; a kind of request YouTube refuses is moved to Apify Proxy by the Actor itself, the others stay direct. The pages of one video's comments are not tied to one proxy address. The embed answer of a private video (HTTP 403) is read as what it is, not as YouTube refusing the run's address.
- Standby mode (`/comments`) in the same code; this build is published as a batch Actor.
