# Changelog of YouTube Comment Scraper — Comments, Replies, Likes (`blackfalcondata/youtube-comment-scraper`) Actor

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

## Changelog

All notable, user-facing capabilities of the YouTube Comment Scraper. This is a
feature log rather than a strict per-release history; it summarizes what the
actor can do.

### Fixes

- **Playlist links work again.** YouTube changed the shape of a playlist's
  contents; a playlist target returned no videos at all while the run reported
  success. Verified after the fix on a live playlist.

- **A run that could not read a page no longer looks like an empty result.** If
  some videos could not be read and the rest had nothing new, the run now fails
  so you can retry it, instead of telling you to check links that were fine. The
  same goes for a run whose results could not be saved.

- **An incremental run with nothing new says so**, instead of printing the
  troubleshooting advice meant for a run that found nothing at all.

- **A stalled connection is retried on a fresh IP** before a target is given up
  on - two of six test runs used to fail on a single stalled request.

- **New and edited replies are noticed.** With replies switched on, a reply added
  or edited under a comment you already received now counts as a change to it;
  before, only the comment's own text did. A reply thread that could not be read
  no longer counts as "the replies are gone", which used to charge you twice.

- **Filters and limits no longer cancel each other out.** With a keyword, date or
  custom filter set, the total limit is applied to what survives the filter, so a
  match further down the list is still reached.

- **The competitor-compatible input names work.** `orderBy`, `maxCommentsPerVideo`
  and their siblings were being overridden by defaults you never set - in one
  case turning a request for 5 comments per video into 100.

- **One video is one source.** The same video pasted twice, or reached through a
  channel and a search, now takes one slot of your video budget instead of two.

- **A competitor-compatible alias is no longer beaten by a default you never
  set.** `sortBy` and `maxComments` are declared with defaults, so the platform
  writes them into every run — and both sorted ahead of their siblings, which
  made `orderBy: "newest"` lose to `"top"` and a per-video cap of 5 lose to 100,
  twenty times the rows and cost asked for. An alias sitting at exactly its own
  default is no longer treated as something you typed.

- **Video links you paste are always processed.** The result limit reserves a
  slot per pasted video, but nothing enforced it: a channel earlier in the list
  could spend the whole budget and the videos you named were skipped. They now
  go first.

- **A keyword or date filter no longer returns zero on a video that had
  matches.** The total limit was spent on comments the filter then discarded, so
  a run whose first matches sat further down stopped before reaching them. The
  limit now applies to what survives the filter.

- **Turning replies on delivers them.** Replies and the comment sort are part of
  the incremental identity now; before, a run with replies switched on shared
  state with one that had them off, found every parent unchanged, and returned
  nothing. The interface language is no longer part of that identity, because
  every request is English regardless — setting it used to reset your state and
  re-deliver everything.

- **A run that could not save its results now fails instead of reporting "no
  results".** Same for a run where every video timed out: that is a run to
  retry, not an empty result and advice to check your links.

### \[0.1.3] — self-audit of the audit fixes

- **Pasted video URLs no longer eat the channel/search budget.** With ten pasted
  videos and `maxVideos: 5`, the channel in the same run contributed nothing —
  the two budgets were being compared instead of added, which broke both halves
  of what the field promises. They now add: every pasted URL is processed, and
  channels and searches still get their own `maxVideos`.

- **A run that hits its charge limit no longer forgets the comments it never
  delivered.** When the run's maximum charge is reached the platform writes only
  part of the batch and reports success; those unwritten comments were counted as
  delivered and recorded as seen, so a later run would skip them. Only what the
  platform accepted now counts.

- **A run that hits its time limit now delivers what it collected.** The
  graceful stop read one environment variable while the platform supplies
  another, so it never engaged: the wall-clock guard ended the process with
  everything still in memory. Measured on a 60-second run — killed at 40 seconds
  having delivered **zero** comments, all of them paid for. Both variable names
  and both timestamp formats are now understood.

- **Aliases now win over the canonical field.** The platform writes every
  declared default into the input, so `maxComments`/`limit`/`query` and friends
  were dead whenever the canonical field had a default — asking for `limit: 1`
  could still collect and charge the default. An alias is only ever typed on
  purpose, so it is the explicit signal; a value that cannot be used for the
  field (a typo in a number) is ignored rather than allowed to shadow yours.

- **An incremental feed no longer stalls at its own head.** Bounding the
  per-video fetch by the total cap meant a monitor with `maxComments: 40` and
  `maxItems: 5` re-read the same five already-seen comments every run and
  delivered nothing, forever. Under incremental the per-video request now stands
  on its own; the total cap still applies to what is delivered.

- **Comments the total cap dropped are no longer remembered as delivered.** When
  the cap moved to after the incremental filter, the state write kept reading the
  pre-cap set — so a comment that was scanned but not delivered was banked as
  seen and would have been suppressed on every later run. The same slip made the
  run counts and the run metadata report more comments than were pushed.

### \[0.1.2] — second-opinion audit fixes

- **Incremental runs no longer starve.** The total comment cap was applied before
  already-seen comments were filtered out, so a run whose first `maxItems`
  comments were all old delivered nothing and never reached the video that had
  new ones. The cap now applies to what is actually delivered.
- **`maxVideos` is honoured in incremental mode too.** It was quietly raised to
  500 there, so a channel monitor set to 10 videos walked up to 500 per run.
- **Comments that never reached the dataset are no longer remembered as
  delivered.** If a batch failed every retry, those comments were recorded as
  seen and suppressed on every later run — permanently lost to the customer.
- **A run where every video came back unreadable now fails**, instead of
  reporting "no results" and suggesting your URLs or filters were wrong.
- The run time limit is now checked between videos during the comment phase, not
  only before it starts.
- Asking for newest-first ordering on a video that cannot offer it now says so.
- **The connected-app export sends comment columns.** It was still sending the
  sibling's video columns (title, channel, views, duration, category), so a
  connected Notion page received rows that were almost entirely empty. It also
  now forwards only what actually reached the dataset, and says so when it sends
  the first 500 of a larger set.
- `maxVideos` documents its real scope (a budget across the run, not per source)
  and its real ceiling; `stateKey`, `incrementalMode` and `includeRunMetadata`
  now describe what the code actually does.

### \[0.1.1] — audit fixes

- **`sortBy: newest` now actually sorts.** The order was declared in the input
  and never sent: YouTube ships the comment order as a second continuation
  token, and the transport always walked the default one. A newest run returned
  top comments.
- **No more duplicate comments on short videos.** The next-page token was found
  by scanning the payload for the first continuation token, which on a last page
  is the sort menu's — so the walk re-fetched the same page and appended the same
  comments again. Videos whose comments fit one page were affected.
- **`country` reaches the request.** The comment fetch was built without locale,
  so the region context fell back to a hardcoded default.
- **`hl` (interface language) removed.** It localized the two strings the actor
  parses back into data, which nulled `publishedAt` on every record; comment text
  is author-written and never localized, so the input could only cost output. The
  `lang`/`language` aliases are accepted and ignored.
- Runs stop fetching videos once the total comment cap is full, instead of
  scanning a whole channel and discarding the surplus. Delivery is unchanged.
- The run plan line quotes the comment budget instead of the video breadth.
- **The pinned comment is no longer delivered twice.** YouTube serves it at the
  top of the first page and again at its own place in the feed, and the second
  copy came back without the pinned flag — one duplicate row per affected video,
  with contradictory `isPinned` values.
- A video with comments turned off is no longer retried through a second network
  path: that is a permanent fact about the video, so the retry only cost time.
  Unreadable payloads and fetch errors — the cases a retry can actually fix —
  still escalate.

### \[0.1.0]

#### Targets

- **Video URLs** — watch links, Shorts, `youtu.be` short links, embed links, or
  bare 11-character video IDs. Every URL you paste is processed.
- **Channel URLs** — a channel URL or a bare `@handle`; the channel's latest
  videos (up to `maxVideos`) become the comment sources.
- **Search Queries** — the top videos matching a keyword become the comment
  sources.
- All three can be combined in one run.

#### Comments

- Top-level comments with text, author display name, author channel id and URL,
  avatar, verified / creator / membership badges, like count (numeric and as
  YouTube renders it), reply count, pinned and creator-hearted flags, edited
  flag, YouTube's relative timestamp and a derived ISO date.
- A permalink (`commentUrl`) that opens the video scrolled to the comment, plus
  the parent `videoUrl`.
- **Replies** — `includeReplies` attaches each thread's replies to their parent
  comment under `replies`. Replies are part of the parent comment's charge and
  are never billed as separate results.
- **Sort** — `top` (YouTube's own ranking) or `newest` (chronological).

#### Limits

- `maxComments` caps comments per video; `maxItems` caps the total the run may
  deliver, so a channel-wide job has a predictable ceiling.
- `maxVideos` bounds what a channel or a search contributes; pasted video URLs
  are never dropped by it.
- `maxRunSeconds` stops the run and pushes what was collected.

#### Repeat runs

- **Incremental mode** — deliver only comments that appeared since the previous
  run, keyed by a state bucket derived from the input (or a `stateKey` you set).
  Records carry `changeType`, `firstSeenAt`, and `lastSeenAt`.

#### Output shaping

- `excludeEmptyFields` drops null/empty fields for lean JSON.
- `includeRunMetadata` appends a run summary record with counts and coverage.

#### Input handling

- Friendly aliases so common alternate field names are accepted: `videoUrl` /
  `url` / `urls` / `startUrls`, `commentsPerVideo` / `maxCommentsPerVideo` /
  `count`, `maxTotalComments`, `orderBy` / `sort`, `query` / `q` / `keywords`,
  `lang`, `geo` / `region` / `gl`, `proxy`.
- Input that resolves to no video (empty, or another actor's input shape) ends
  the run as a controlled success: no items, no per-result charges.

#### Reliability

- Per-video isolation: one unreadable video never aborts the rest of the run.
- Comment fetches that come back empty are automatically retried through a
  different network path before the video is reported as having no comments.
