apihq/youtube-transcript-scraper · YouTube

YouTube Transcript Scraper

Scrape YouTube transcripts, captions, and subtitles as timestamped JSON. One video or a batch of 50. No YouTube Data API key or quota, no browser.

$0.0030/transcript · failed items $0.0000 — on your existing Apify account, a one-item first run costs under a cent.

What does YouTube Transcript Scraper do?

Scrape YouTube transcripts, captions, and subtitles as clean timestamped JSON. No YouTube Data API key or quota, no browser. One video or batch up to 50. Returns caption segments plus video metadata and languages. Pay only for successful transcripts at $3 per 1,000; failed videos never charge.

Best for

Use it where videos become text: RAG pipelines, LLM training data, search indexes over spoken words, sentiment analysis, subtitle tooling. The stable error codes matter most when transcripts feed an automated pipeline and one captionless video must not take down the batch.

Use something else when

It reads one video at a time, in batches of up to 50 IDs. It does not crawl a whole channel or playlist. Collect the IDs first with the YouTube Channel Scraper or YouTube Shorts Scraper, then feed them here.

Price
$3.00 per 1,000 transcripts · failed items $0
Usage on Apify
7,000+ transcripts delivered

2,500+ Actor runs recorded by Apify in the 30 days ending 2026-07-20; 3,400+ all-time.

Example run

input
{ "videoIds": ["jNQXAC9IVRw", "00000000000"] }

outcome

  • 1 success: true transcript for jNQXAC9IVRw ("Me at the zoo") — billed
  • 1 success: false row, code: PLAYABILITY, for the unplayable ID — not billed
  • Run status: SUCCEEDED
  • Charged: 1 transcript = $0.003

Good input returns billed rows. Bad input returns free error rows in the same dataset, and the run still succeeds.


Why pipelines pick it

You pay only for transcripts delivered

A video with no fetchable transcript returns success:false and costs nothing. A batch of only captionless videos costs $0.

Every failure is machine-readable

Each failure carries a stable code such as NO_CAPTIONS or PLAYABILITY. Your pipeline branches on the code instead of parsing error text.

A hard 30-second deadline per video

If the upstream stalls, the actor writes an unbilled success: false row with code DEADLINE_EXCEEDED (status_code 504) and continues the batch, instead of hanging for an hour.

No YouTube Data API key or quota

The official Data API gates caption downloads behind the video owner's OAuth. This actor takes a plain video ID and returns JSON.

Best for: Use it where videos become text: RAG pipelines, LLM training data, search indexes over spoken words, sentiment analysis, subtitle tooling. The stable error codes matter most when transcripts feed an automated pipeline and one captionless video must not take down the batch.


Input & output

input example
{
  "videoIds": [
    "jNQXAC9IVRw",
    "dQw4w9WgXcQ",
    "kJQP7kiw5Fk"
  ],
  "language": "en",
  "metadata": true
}
output — success (billed)
{
  "success": true,
  "video_id": "jNQXAC9IVRw",
  "language": "en",
  "transcript": [
    { "text": "All right, so here we are, in front of the elephants", "start": 1.2, "duration": 2.16 },
    { "text": "the cool thing about these guys is that they have really really really long trunks", "start": 5.318, "duration": 7.298 },
    { "text": "and that's pretty much all there is to say", "start": 16.881, "duration": 2 }
  ],
  "is_auto_generated": false,
  "available_tracks": [
    { "language_code": "en", "language_name": "English", "is_auto_generated": false },
    { "language_code": "de", "language_name": "German", "is_auto_generated": false }
  ],
  "metadata": {
    "title": "Me at the zoo",
    "author_name": "jawed",
    "channel_id": "UC4QobU6STFB0P71PMvOGN5A",
    "duration_seconds": 19
  }
}
output — failure (free, same dataset)
{
  "success": false,
  "video_id": "00000000000",
  "code": "PLAYABILITY",
  "error": "Video 00000000000 is not playable: This video is unavailable",
  "request_id": "req_911f37d2e55644ff9d9e4a3f",
  "status_code": 403
}

Branch on the success field to split hits from misses. Quote the request_id in any support issue and we can trace the exact request.

output fields

fieldtypewhat it is
successbooleantrue for a fetched transcript (billed), false for a video with no fetchable transcript (free).
video_idstringThe 11-character YouTube video ID.
languagestringLanguage code of the selected caption track.
transcriptarrayTime-coded caption segments. Each has text, start, and duration.
is_auto_generatedbooleanTrue if the selected track is YouTube's ASR.
available_tracksarrayEvery caption track the video exposes, with language code and name.
metadataobjectVideo title, channel name and URL, thumbnail, channel ID, duration in seconds. Present when metadata: true (default).

Error codes, stable across releases

Every failure record carries one of these machine-readable codes. None of them are ever charged.

codebilledmeaning
NO_CAPTIONS$0.0000The video has no caption track at all.
PLAYABILITY$0.0000The video is private, deleted, age-gated, or otherwise not playable.
EMPTY_TRANSCRIPT$0.0000The caption track parsed to zero segments. Treated as a failure, so you never pay for a blank transcript.
VALIDATION_FAILED$0.0000The input was not a valid 11-character video ID.
DEADLINE_EXCEEDED$0.0000The 30-second per-video deadline was hit. Returned as an unbilled row with status_code 504.
PO_TOKEN_REQUIRED$0.0000YouTube demanded a proof-of-origin token for this request.
CAPTIONS_TIMEOUT$0.0000The caption fetch itself timed out.
NO_INPUT$0.0000No video IDs were provided.

Every error code across the eight APIs, in one reference →


What a run costs

per transcript$0.0030
per 1,000 transcripts$3.00
per failed item$0.0000
per-run start fee$0.00005

The charge fires only when a result is delivered, and platform compute is included in the per-result price. To cap the spend of a run, set a limit in Apify's Run Limits panel. The actor stops at the cap and reports how far it got.

How pay-per-result billing works →


What this actor doesn't do

  • It reads one video at a time, in batches of up to 50 IDs. It does not crawl a whole channel or playlist. Collect the IDs first with the YouTube Channel Scraper or YouTube Shorts Scraper, then feed them here.
  • It reads caption tracks that already exist, manual or auto-generated. It does not transcribe audio. A video with no captions returns success:false with code NO_CAPTIONS.
  • It reads public videos only. Private, members-only, and age-gated videos return success:false.

Frequently asked questions

Do I need a YouTube Data API key?
No. The Actor reads YouTube's public data directly and does not consume Google API quota.
What happens if a video has no captions?
It comes back as a success:false record with code NO_CAPTIONS in the same dataset. You are not charged for it.
Which languages are supported?
Every language the creator uploaded. Pass a language code (en, de, en-US) to pick a track; omit it and the Actor prefers manual English, then auto-generated English, then the first available track.
Can I get transcripts for a whole channel?
Not directly. Collect the channel's video IDs first with the YouTube Channel Scraper (long-form) or YouTube Shorts Scraper (Shorts), then feed them here in batches of 50.
How does billing know a video failed?
Billing fires on an explicit per-transcript charge event, not on dataset writes. The Actor only fires it when a transcript is delivered, so success:false records sit in your dataset for free.
What happens if YouTube rate-limits the request?
The request retries with exponential backoff. If it still cannot fetch within the 30-second deadline, the video comes back as success:false with code DEADLINE_EXCEEDED. You are not charged.

Guides for this API


Automation templates


Comparisons


Pairs with

Run it on the Apify account you already have

Paste one input into the actor's console and check the dataset it returns. A one-item first run costs under a cent — no new subscription, pay only for delivered results.

Get one transcript