YouTube Transcript Scraper & API: Captions, Subtitles, Shorts avatar

YouTube Transcript Scraper & API: Captions, Subtitles, Shorts

Pricing

from $5.00 / 1,000 transcripts

Go to Apify Store
YouTube Transcript Scraper & API: Captions, Subtitles, Shorts

YouTube Transcript Scraper & API: Captions, Subtitles, Shorts

Bulk YouTube transcripts from videos, Shorts, channels, playlists and searches, in the language spoken. Text with timestamps, SRT and VTT, chapters, exact comment count and subscribers, and a watch mode that returns only new videos. Videos without captions are not charged.

Pricing

from $5.00 / 1,000 transcripts

Rating

0.0

(0)

Developer

Quarra Labs

Quarra Labs

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

YouTube Transcript Scraper: Videos, Shorts, Channels, Playlists, Search

Get YouTube transcripts (subtitles and closed captions) in bulk, without a YouTube account or API key. Give it video URLs, Shorts, channels, playlists or search terms; each video comes back with its full transcript as plain text ready for AI and LLM pipelines, as timestamped segments and, if you want, as SRT and VTT subtitles, with the language you asked for, the list of every caption track available, chapters and the video's details (views, likes, exact comment count, thumbnail, channel subscribers). Export as JSON, CSV or Excel (see Spreadsheets), or read it through the Apify API. $5 per 1,000 transcripts, plus a small start fee per run; videos without captions and errors are free.

Three things you would otherwise build yourself: a whole channel or playlist in one run, a monitoring mode that returns only the videos you have not received yet, and a free record that says exactly why a video has no transcript.

Quick start

  1. Paste a video, Short, channel or playlist link (or @handle) into Videos, channels or playlists, or words into Search queries.
  2. Click Start.
  3. Read the transcripts in the run's Output tab, or export them as JSON, CSV or Excel.

Like any Apify Actor, it can also be run and read through the Apify API, scheduled, and connected to webhooks, Make, Zapier, n8n or Apify's MCP server for AI agents.

What you can transcribe

InputExamplesWhat you get
Videoshttps://www.youtube.com/watch?v=8jPQjjsBbIc, https://youtu.be/8jPQjjsBbIc, 8jPQjjsBbIcthat video
Shorts, live, embedhttps://www.youtube.com/shorts/…, /live/…, /embed/…that video
Channels@TED, https://www.youtube.com/@TED/shorts, https://www.youtube.com/channel/UC…its latest videos, Shorts, past streams or all uploads (channelContent, or the tab in the URL), newest first
Playlistshttps://www.youtube.com/playlist?list=PL…, PL…the playlist's videos in order
Searchmachine learning lecture in searchQueriesthe videos YouTube returns, by relevance or popularity (searchSort)

Mix them freely in one run. maxVideosPerSource caps each channel, playlist and search (default 10, up to 10,000). A video that appears in two of your sources is transcribed and charged once, and still counts in the window of each source, so no source ever returns more than maxVideosPerSource videos. A channel given twice under different forms (@TED, its /channel/UC… URL, /c/TED, /user/…) is read once per tab: one window, not two.

A @handle is checked against the channel YouTube leads to, the way YouTube compares handles (case, accents and character width do not matter: @ChefAmelie is @ChefAmélie); if that channel carries another handle, you get a free channel_not_found record, never another channel's videos. Handles in any script work (@বাংলা, @ChefAmélie). When YouTube leads a handle to a channel written differently, the record says which channel it actually is. Lists are read page after page to their end; if YouTube ever stops returning the next page, the run says so in its status and in OUTPUT (listIncomplete) instead of pretending the channel is shorter.

Channels come newest first. With channelSort: popular (or ?sort=p in a tab URL) the Videos and Shorts tabs come most viewed first, all the way down the channel. Combined with publishedAfter, the Videos tab is read from the most recent video back to your date and those videos are ranked by views (view counts as shown in YouTube's lists, rounded); the Shorts tab has no dates in YouTube's lists, so Shorts then come newest first, reading stops at the first Short older than your date, and the run says so. @name/live gives the video of the channel's live stream in progress.

What we measured

On the Apify platform on 9 October 2026, at the default memory (512 MB) unless stated:

  • 62 videos taken from a channel (@TED), four searches in three languages (English, French, Spanish), a Short and a video without captions: 57 transcripts, and 5 free missing records with the reason (3 without any captions, 1 whose captions held no speech, 1 live stream still in progress). Where YouTube marks the original audio track (46 of the 57), the transcript is in that language.
  • 62 videos in 77 seconds, three of them tutorials of 12 to 16 hours.
  • Three lectures that YouTube's AI has dubbed into 11 to 19 languages: all three come back in English, their original language.
  • 12 videos of a podcast channel, up to 5 h 16 min each (39.5 hours of speech), with SRT and VTT: 12 of 12 in 89 seconds with 256 MB, the smallest memory this Actor accepts (the run peaked at 134 MB).
  • The default input (one video) runs in about 4 seconds.
  • A run of 15 videos restarted by the platform in the middle (we forced it after 6 records) finished with 15 records for 15 videos: none repeated, and the transcripts counted for billing match the transcripts delivered (14 of 14).

A video with captions comes back with its transcript, or with a free record that says why; a run never "succeeds" with empty output when the failure is on our side or YouTube's. Every record says which language you got, whether it was the one you asked for (requestedLanguageFound), and lists all the tracks of the video (availableLanguages).

Languages

  • Leave languages empty to get each video in the language spoken in it: the creator's captions in that language if they exist, otherwise YouTube's automatic captions.
  • Or give a list in order of preference (["en", "es"]). For each language, captions written by the creator come first, then automatic captions. en also matches en-US and en-GB.
  • If none of your languages exists on a video, you get the spoken language with requestedLanguageFound: false. Turn off useAnyLanguage to get a free missing record instead, with the list of available languages in the reason.
  • "The language spoken" is the video's original audio track as YouTube marks it (originalLanguage). Many videos are now dubbed by YouTube's AI into a dozen languages, each with its own automatic captions: those tracks are machine translations, so we never return them, neither as the spoken language nor as a language you asked for. They are listed in availableLanguages with isAutoDubbed: true.
  • Codes are read the way you type them: en_US, pt-BR, he (YouTube's iw), or names such as English. A code we cannot read is ignored and said in OUTPUT.inputNotes; the rest of the run goes on.
  • We do not offer translation: YouTube's machine translation is too unreliable for us to charge for. Ask for a language and you get the video's own captions in it when they exist; otherwise the rules above apply.

Output

One record per video. A transcript (status: "ok"), shortened here:

{
"status": "ok",
"videoId": "8jPQjjsBbIc",
"url": "https://www.youtube.com/watch?v=8jPQjjsBbIc",
"title": "How to stay calm when you know you'll be stressed | Daniel Levitin | TED",
"channel": {
"id": "UCAuUUnT6oDeKwE6v1NGQxug",
"name": "TED",
"handle": "@TED",
"url": "https://www.youtube.com/@TED",
"subscriberCount": 27900000,
"thumbnailUrl": "https://yt3.ggpht.com/ytc/AIdro_koIFcCOrvh0KThLNOiazAIDu6hcs8bjkGNwe1f6A_OYm8=s800-c-k-c0x00ffffff-no-rj"
},
"publishedAt": "2015-11-23T16:58:55Z",
"durationSeconds": 740,
"viewCount": 20051236,
"likeCount": 268984,
"commentCount": 4076,
"commentsDisabled": false,
"thumbnailUrl": "https://i.ytimg.com/vi/8jPQjjsBbIc/maxresdefault.jpg",
"category": "Science & Technology",
"isShort": false,
"isLive": false,
"isLiveNow": false,
"isUnlisted": false,
"isFamilySafe": true,
"originalLanguage": "en",
"language": "en",
"languageName": "English",
"isAutoGenerated": false,
"requestedLanguageFound": null,
"availableLanguages": [
{ "languageCode": "ar", "name": "Arabic", "isAutoGenerated": false, "isAutoDubbed": false },
{ "languageCode": "en", "name": "English", "isAutoGenerated": false, "isAutoDubbed": false },
{ "languageCode": "en", "name": "English (auto-generated)", "isAutoGenerated": true, "isAutoDubbed": false }
],
"chapters": null,
"transcript": "A few years ago, I broke into my own house. I had just driven home, it was around midnight in the dead of Montreal winter, …",
"segments": [
{ "start": 13.24, "end": 15.8, "duration": 2.56, "text": "A few years ago, I broke into my own house." },
{ "start": 16.88, "end": 18.096, "duration": 1.216, "text": "I had just driven home," }
],
"segmentCount": 260,
"wordCount": 2232,
"characterCount": 12360,
"billedTranscripts": 1,
"missingReason": null,
"errorCode": null,
"error": null,
"retryable": null,
"warning": null,
"input": "https://www.youtube.com/watch?v=8jPQjjsBbIc",
"inputType": "video",
"position": null,
"scrapedAt": "2026-10-07T19:03:48.620Z"
}

The real record lists the 41 caption tracks of this video. position and warning are always there (null here); srt, vtt, description and keywords appear when you ask for them, truncatedFields only when it applies. A video without captions comes back as a free record that holds the reason and the tracks it does have, and no video details (no title, counts or description: those come with transcripts):

{
"status": "missing",
"videoId": "NsPw4HIDK_k",
"url": "https://www.youtube.com/watch?v=NsPw4HIDK_k",
"availableLanguages": [],
"missingReason": "no captions on this video",
"errorCode": null,
"error": null,
"retryable": null,
"warning": null,
"input": "NsPw4HIDK_k",
"inputType": "video",
"position": null,
"scrapedAt": "2026-10-09T19:24:26.093Z"
}

Fields that need a word of explanation

  • status: ok (transcript, charged), missing (the video exists but there is no transcript you can get: no captions, none in your languages, live stream in progress, premiere not started; free) or error (private, deleted, age-restricted or members-only video, unknown channel, unreadable line, or YouTube not serving the page; free).
  • segments: times in seconds, as numbers. Automatic captions on YouTube scroll, so each line stays on screen under the next one; we trim duration so that segments do not overlap, which gives clean subtitle files. Some manual captions carry every line twice (same start, same duration, same text: an outline effect on screen); each such line is kept once, while a line really said twice (at another time) stays.
  • commentCount: the exact number of comments, as the video's comment section counts it; null with commentsDisabled: true when comments are turned off (videos made for kids, for example). channel.subscriberCount is rounded the way YouTube shows it (27.9M gives 27900000) and null if the channel hides it or the video's page does not show it (videos uploaded by a VEVO channel, for example). thumbnailUrl is the largest thumbnail the video has. Rarely, the video's page cannot be read: the comment count, subscriber count and channel avatar are then null (commentsDisabled too), and the transcript is delivered and charged as usual.
  • transcriptFormat: both (default), text or segments. includeSrt and includeVtt add the srt and vtt fields: the full text of a ready-to-save .srt or .vtt file.
  • truncatedFields: rare. When a very long video's record would exceed Apify's size limit for one record (about 9 MB), vtt, then srt, then segments are left empty and listed here; transcript is always complete.
  • removeSoundTags removes [Music], [Applause], (laughter) and similar tags, handy before an LLM.
  • chapters: the chapters the creator declared in the description, with YouTube's own rules (first one at 0:00, at least three, each at least 10 seconds). Null when there are none.
  • isShort: true for a Short. isLive: a live stream, past or present (not a premiere); isLiveNow: still live.
  • wordCount splits on spaces; for Chinese, Japanese or Thai, use characterCount.
  • billedTranscripts: the transcripts charged for this record: 1, or one per 10 hours started for a video over 10 hours (see Pricing); 0 for a free re-delivery.
  • missingReason also covers a past live stream without a recording, captions that hold only sound tags such as [Music] with a few stray letters, automatic captions with fewer than 5 spoken characters in all (a Chinese, Japanese or Korean character counts for three; captions written by the creator are never refused for being short), all free with or without removeSoundTags, and videos skipped by excludeMusicVideos. Speech is measured in letters, not words, so Japanese, Chinese or Thai sentences without spaces count fully.
  • errorCode and retryable (all error records are free):
    • final (retryable: false): private_video, video_unavailable, age_restricted, members_only, geo_restricted (the uploader has restricted this video by country, so it cannot be read), paid_video, channel_not_found, channel_empty, no_live_now, playlist_not_found, no_results, invalid_url, bad_input (the input as a whole cannot run);
    • worth retrying later (retryable: true): blocked and network (YouTube did not serve the page, or did not answer), login_required, content_check and unplayable (YouTube asks for sign-in or a confirmation, or does not play the video at that moment), site_changed, listing_failed and unexpected (YouTube changed or failed to serve a page, or an error on our side), watch_busy (see Only new videos);
    • captions_too_large: a caption track far larger than any real track for a video of that length, typically junk uploaded on purpose; it is never delivered cut short and not charged (retryable: false);
    • long_video_over_budget: a video over 10 hours that what was left of the run's maximum charge or maxItems did not cover; not delivered, not charged (retryable: true, with a higher limit);
    • run_cost_limit: a video not read because the run reached its limit for work that gives no transcript (see Pricing); not charged; retryable: true when a new run can read it, false when its captions are far larger than speech of that length can produce.
  • Input lines that are not understood get one invalid_url record each, up to 10, then one record that counts the rest; OUTPUT.badInputs lists the first 100 and OUTPUT.badInputCount gives the total. The other lines of the input run normally.
  • warning: rare; something the record could not include, said plainly (for example YouTube did not return a video's date and category).
  • includeDescription adds description and keywords (the video's tags).
  • input and inputType tell which of your inputs produced the record; position is the video's rank in its channel, playlist or search (1 = first, newest first for channels). Records are written as soon as each video is done, so sort by input and position to get the source's exact order.

CSV and Excel

A transcript is long and segments holds hundreds of lines per video, so the full record does not fit a spreadsheet: Apify's CSV and Excel exports stop at 2,000 columns (checked on 9 October 2026). For a spreadsheet, export the Transcripts view (one row per video: ID, title, language, text, URL, input, position), or run with transcriptFormat: "text".

Titles, transcripts and handles come from YouTube as their authors wrote them; we do not rewrite them. A cell that starts with =, +, - or @ (a channel handle, for example) may be read as a formula when a CSV file is opened in Excel or Google Sheets. Apify's Excel export writes such cells as text, not as formulas (checked on 9 October 2026), so prefer it to the CSV for a spreadsheet. Excel cuts any cell after 32,767 characters (roughly 6,000 words, or half an hour of speech): for longer videos, use JSON, which keeps the whole text.

The dataset has three views (Overview, Transcripts, Video details). The run's summary is the OUTPUT record of the default key-value store: per input, the channel or playlist it resolved to, videos listed, transcripts, missing, errors, and videos skipped because they were already delivered or published before your date.

Only new videos (monitoring)

Turn on onlyNewVideos, schedule the Actor (hourly, daily), and each run returns only the videos that earlier runs did not deliver for the same channel, playlist or search. Nothing is charged twice. A run with nothing new ends as Succeeded with "Nothing new since the last run of this watch" and charges only the start fee.

  • Window. For channels, uploads playlists (UU…) and searches, maxVideosPerSource is the window checked at each run: with 10, the 10 latest videos are looked at, and the ones already delivered are skipped without being downloaded again. When nothing is new, a run reads one page per channel. If a source got more new videos than the window since the last run, the run delivers the latest ones and says so; the next runs go on with the older new videos, so nothing in between is lost.
  • Playlists are checked in full at each run (first 2,000 videos; YouTube adds new videos at the end of most playlists), and up to maxVideosPerSource new videos are delivered per run. Searches: add publishedAfter (for example 3 days) to keep the watch on recent videos.
  • Videos without captions yet are checked again after 6 hours, then 12, then every 24 hours, for 3 days (YouTube adds automatic captions some time after upload). You get one free missing record; re-checks that still find nothing add no record. Live streams and premieres are followed until they end; their transcript comes in the first run that checks them after the end.
  • Memory. The memory is a key-value store named quarra-youtube-watch in your own Apify account (video IDs, no transcripts). Without watchName, a watch is identified by its channels, playlists and searches; set watchName to keep one memory while you change the sources, and always for a watch made only of video links. If a run is killed, the next one delivers what was missing without charging twice; the status says what happened.
  • Limits. One run per watch at a time (a second one ends with a free watch_busy record); up to 500 sources per watch. A run with nothing new checks a limited number of sources: for a watch of hundreds of channels, schedule it more often or split it into several watches (watchName). The status always says how many sources were not checked; the next run starts with them.

Limits in Only new videos: limits at the end of this page.

Dates

publishedAfter takes a date (2026-10-01), a date and time in UTC (2026-10-01T08:00:00Z) or a duration (7 days, 2 weeks, 24 hours). Older videos are skipped before their transcript is downloaded and are never charged. For channels, reading stops at the first older video. For searches, YouTube's own upload-date filter is applied as well, so you get recent videos rather than none.

Input examples

The latest 20 videos of two channels, in English when available:

{
"urls": ["@TED", "https://www.youtube.com/@veritasium"],
"maxVideosPerSource": 20,
"languages": ["en"]
}

A daily watch of a channel and a search, text only, for an LLM pipeline:

{
"urls": ["@TED"],
"searchQueries": ["machine learning lecture"],
"maxVideosPerSource": 25,
"onlyNewVideos": true,
"watchName": "ml-daily",
"publishedAfter": "3 days",
"transcriptFormat": "text",
"removeSoundTags": true
}

Subtitle files for a video and a Short:

{
"urls": ["https://youtu.be/8jPQjjsBbIc", "https://www.youtube.com/shorts/QyVlUmluLhs"],
"transcriptFormat": "segments",
"includeSrt": true,
"includeVtt": true
}

From your own code, with the Apify client for Python (the JavaScript client works the same way):

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("quarra/youtube-transcript-scraper").call(
run_input={"urls": ["@TED"], "maxVideosPerSource": 5, "transcriptFormat": "text"}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["status"], item["videoId"], (item.get("transcript") or "")[:80])

Pricing

Pay per result: $5 per 1,000 transcripts ($0.005 each, the same on every Apify plan), plus a start fee of $0.005 per GB of memory per run (1 GB minimum: $0.005 at the default 512 MB, $0.02 at 4 GB). A video over 10 hours counts as one transcript per 10 hours started (a 24-hour live replay counts 3; without a duration from YouTube, the length of its captions counts; billedTranscripts in each record says how many). Videos without captions, errors and duplicates are free. Platform usage is included. A run that fails before its first transcript charges only its start fee; transcripts delivered before a failure stay in your dataset and are charged once.

Your maximum charge per run is never exceeded: the run stops at the last transcript it can charge and says so in its status; a long video that would go over it is not delivered and not charged, and its record says why. maxItems caps the charged transcripts of a run: ask for 10, get 10 (plus the free records met on the way).

Videos without captions are free, so a run cannot read them without limit: when it keeps meeting videos that give no transcript (no captions, another language, failed inputs, lists read for nothing, re-checks), it stops early and says why. A list that opens with a long run of videos without captions can stop before delivering anything (in our tests, after a handful), so split such lists. A run that keeps finding transcripts goes on. One run takes up to 20,000 URLs, 1,000 searches and 20 languages.

Run (default memory)Price
1 video$0.010 ($0.005 start + $0.005)
A channel's latest 100 videos, 8 of them here and there without captions$0.465
A 24-hour live replay$0.020 ($0.005 start + 3 × $0.005)
1,000 transcripts in one run$5.005

Apify's free plan includes $5 of usage a month, with no credit card required (apify.com/pricing, checked on 9 October 2026): enough to try this Actor on your own videos.

Use cases

  • Feed transcripts to an LLM or a RAG index: summaries, Q&A over a channel, course notes.
  • Research and media monitoring: what a set of channels or a topic said this week, in their own words.
  • Content repurposing: blog posts, newsletters, quotes and timestamps from your own videos.
  • Accessibility and localization: subtitle files to edit, translate or re-upload.
  • Dataset building for analysis: language, length, topics across thousands of videos.

Limits

  • Songs. For music videos, YouTube's automatic captions transcribe the lyrics as if they were speech; they come back as transcripts and are charged like any other. We found no rule that tells a song from a talk with certainty, so the choice is yours: excludeMusicVideos skips every video YouTube files under Music, before its transcript is downloaded and without charge, with a free missing record (a lesson or interview filed under Music is skipped too; a song filed elsewhere, under Entertainment for instance, is not). Captions made only of sound tags such as [Music] are never charged.
  • No captions, no transcript. In a sample of 150 varied videos we drew from YouTube searches in 12 languages (7 October 2026), 19% had no captions at all (silent Shorts, live streams, music). This Actor reads captions; it does not transcribe audio. Those videos come back as free missing records.
  • Automatic captions are what YouTube generates: punctuation is often sparse and speakers are not named.
  • Age-restricted and members-only videos need a signed-in account, and paid videos a purchase; we do not use accounts, so they come back as free error records.
  • Live streams have no transcript until they end, and premieres none until they have aired.
  • A list with few captions can stop early (see Pricing): split it.
  • No translation (see Languages). Comments are counted, not collected.
  • Chapters are the ones declared in the description; YouTube's automatic chapters are not included.
  • A search inside a channel (@name/search?query=…) and a channel's playlist, community or podcast pages are not supported: they come back as a free invalid_url record. @name/live gives the channel's current live stream.
  • Search results are the ones YouTube shows a signed-out visitor with its interface in English; a search can return fewer videos than asked for. With publishedAfter, YouTube's results often hold older videos: the Actor reads up to 5 result pages per 20 videos asked, and if that was not enough, the run says so (listIncomplete in OUTPUT).
  • A run lasts at most its timeout (1 hour by default for this Actor). For a channel of thousands of videos, raise the timeout or cap the run with maxItems; a run that reaches its timeout keeps the transcripts it delivered and says so.

FAQ

Is it legal to scrape YouTube transcripts? This Actor reads only publicly available data: the captions YouTube shows to any visitor who is not signed in. It does not access private, members-only or age-restricted videos. Transcripts reproduce what people say, which may be protected by copyright and may contain personal data. You are responsible for making sure your use (research, analysis, quotation, accessibility) complies with the laws and terms that apply to you, including data-protection rules such as the GDPR in Europe; if in doubt, consult a lawyer. We do not receive or store your results: they stay in your Apify account, and the watch memory (video IDs only, no transcripts) is a store in your own account.

Why was a long video charged as several transcripts? A transcript of a 24-hour live replay is as large as dozens of ordinary videos and takes as much to process, so a video over 10 hours counts as one transcript per 10 hours started: 10 h 30 counts 2, 24 hours counts 3. The duration is read before the transcript is downloaded: if what is left of your maximum charge or maxItems does not cover it, the video is skipped, uncharged, with a record saying so. When YouTube gives no duration (some finished live streams and premieres), the length is read from the captions' timings instead (up to 24 hours), the record's warning says so, and the same rule applies. Under 10 hours, one transcript, whatever the length.

Do I need a YouTube API key or any setup? No. Leave the Connection setting on its default (automatic): it is included in the price.

How fast is it? About 4 seconds for one video and 77 seconds for 62 videos at the default 512 MB (measured on 9 October 2026; three of those videos were tutorials of 12 to 16 hours). More memory reads more videos at once; the start fee is the same up to 1 GB.

Why is a video "missing" when I can see captions on YouTube? Check availableLanguages and missingReason: the video may have captions only in languages you did not list while useAnyLanguage is off, or it may be a live stream still in progress. If a video shows captions on YouTube and you get missing with "no captions on this video", please open an issue with the URL and the run ID: we look at every report.

What happens when YouTube changes something? We fix breaking changes as a priority; if a run fails, open an issue with its run ID. A run never ends as Succeeded with empty output when the failure is on our side or YouTube's: it ends as Failed and its status says what went wrong; if it fails before its first transcript, only the start fee is charged. A video YouTube does not deliver comes back as a free error record, with retryable: true when a later run may succeed.

Only new videos: limits

  • Re-checks: up to 50 per run (videos waiting for captions, live streams, premieres), the longest-waiting first; the status says how many were left for the next run. Removing a source drops its pending re-checks.
  • Runs cut short: if a run stops before its last source (time limit, maxItems, maximum charge), the next run starts with the sources it did not reach.
  • More new videos than the window: the source's entry in OUTPUT.inputs has moreNewVideos: true (OUTPUT.watch.sourcesWithMoreNewVideos counts such sources); each later run passes over at most 2,000 already delivered videos to reach the older new ones.
  • Playlists: the first 2,000 videos are checked at each run; videos without captions do not take the places of the maxVideosPerSource new videos.
  • Errors: private, deleted, paid, age-restricted and members-only videos and past live streams without a recording are reported once, then no longer checked. A video YouTube did not serve only for a while gets its error record once; later runs that meet the same error add no record (counted in OUTPUT as stillFailing).
  • Several sources: a video delivered for one source of a watch is not delivered again for another source or as a link. Video links share one memory per watch: add new links from run to run, and only those are transcribed.
  • Killed runs: after a run killed without the graceful option (or out of memory), the videos it may have charged are delivered again for free, possibly over several runs; some of these rows may repeat rows of the killed run, and the status says how many.
  • Sources taken out: a source left out of the input is remembered for 30 days (up to about 2,500 sources in all), so putting it back delivers nothing twice.
  • First run without watchName: a large watch may first spend one or more runs identifying its channels (status "Setting up this watch", nothing delivered); the next runs go on, then deliver. With a watchName, this is not needed.