Skip to main content
Thirdwatchthirdwatch
Social & news

Audit Which YouTube Videos Only Have Auto-Generated Captions

Check at scale whether videos ship human-written captions or only YouTube's auto-generated ASR track — an accessibility and content-quality audit.

Editorial illustration for social & news
Sep 16, 2026 · 3 min read · 591 words
View the Apify scraper →

Auto-captions exist almost everywhere — the question is whether a human ever wrote real ones. Thirdwatch's YouTube Subtitle Scraper returns every caption track a video offers as timestamped segments plus full video metadata — no API key, no OAuth.

Skip the setup: Run this as a ready-to-go task on Apify — pre-loaded with the configuration from this guide.

Why audit caption coverage

Auto-generated captions are better than nothing, but they mangle names, jargon and anything spoken over music. For a channel audit or accessibility review you need to know which videos have a real caption track and which are ASR-only — and nothing on the watch page reports that at scale.

The Actor labels every returned track manual or auto via captionSource and reports the full availableLanguages list, turning an hours-long manual audit into one run.

The subtitle scraper reads the public caption endpoints directly, so the batch path is a list of URLs in and transcript rows out.

How does this compare to the alternatives?

Approach Cost model Coverage Effort
YouTube Data API + OAuth Quota-limited, free tier Only authorised captions / own channel Key + OAuth setup
Manual transcript-panel copy Analyst hours One video at a time Doesn't scale
Thirdwatch YouTube Subtitle Scraper Pay per video row All public caption tracks Zero setup

Why this Actor

  • Manual and auto-generated tracks both supported — captionSource labels which you got.
  • Every segment carries startMs, durationMs and text, so timestamp-level alignment survives.
  • availableLanguages lists every track the video offers — discovery and extraction in one pass.
  • Each video gets its own proxy session with a fresh-exit retry, so multi-video batches stay reliable.
  • Full metadata on the row: title, channel, duration, view count, upload date.

How to do it in 3 steps

Step 1: Configure the input

Set the inputs as shown below — videoUrls takes the targets, languages picks the caption language(s) and preferManual chooses human-written over auto-generated tracks.

Step 2: Run the Actor

Run it from the console, the API, or the linked saved task. One dataset row is written per video.

Step 3: Use the output

Each row carries the video metadata, the caption track as segments (with startMs/durationMs/text), and the joined transcript string.

{
  "videoUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "languages": [
    "en"
  ],
  "preferManual": false,
  "proxyCountry": "US"
}

Each dataset row looks like:

{
  "videoId": "dQw4w9WgXcQ",
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "title": "Rick Astley - Never Gonna Give You Up (Official Video)",
  "channel": "Rick Astley",
  "language": "en",
  "captionSource": "manual",
  "segmentCount": 61,
  "segments": [
    {
      "startMs": 18170,
      "durationMs": 2290,
      "text": "We're no strangers to love"
    }
  ],
  "transcript": "We're no strangers to love ..."
}

What to watch for

Heavily scraped videos sometimes return a 429 on the caption file even after the fresh-exit retry — those come back as error rows, not silent gaps. Videos with no captions at all behave the same way, which is itself a useful audit signal.

Related use cases

Run the YouTube Subtitle Scraper on Apify Store — pay per result, free to try, no credit card to test.

Frequently asked questions

Do I need a YouTube API key?

No — the Actor reads the public caption endpoints, so there is nothing to provision.

What languages work?

Any language the video ships a track for. Pass ISO 639-1 codes in `languages`, or omit it and read `availableLanguages` on the row to see what exists.

Auto captions or human captions?

Both are supported. `preferManual` prefers human-written tracks; `captionSource` on the row tells you which type was actually returned.

Why did one video return an error row?

Heavily scraped videos occasionally hit a caption-side rate limit. The Actor retries once on a fresh proxy session; a persistent failure comes back as an `error` row you can retry.

Can I get plain text without timestamps?

Yes — `transcript` is the segments joined into one string. Keep `segments` too if you want timestamp-level retrieval.

How many videos per run?

Dozens comfortably — each video gets an isolated proxy session, so batch size is bounded by run timeout rather than rate limits.

Related