YouTube Transcript Scraper API | Captions & Subtitles avatar

YouTube Transcript Scraper API | Captions & Subtitles

Pricing

from $9.00 / 1,000 successful video transcripts

Go to Apify Store
YouTube Transcript Scraper API | Captions & Subtitles

YouTube Transcript Scraper API | Captions & Subtitles

Extract YouTube transcripts, captions, subtitles, and timestamped transcript segments from YouTube URLs, Shorts, or video IDs. No YouTube API key required. Residential proxy enabled. Use from Apify Console or API.

Pricing

from $9.00 / 1,000 successful video transcripts

Rating

0.0

(0)

Developer

Inus Grobler

Inus Grobler

Maintained by Community

Actor stats

1

Bookmarked

28

Total users

1

Monthly active users

2 days ago

Last modified

Share

Extract timestamped YouTube transcripts, captions, subtitles, and transcript segments from YouTube video URLs, Shorts URLs, or video IDs. This Actor is for SEO research, AI summaries, content repurposing, media monitoring, RAG pipelines, and teams that need YouTube transcript data without using the official YouTube Data API.

The Actor returns clean segment-level rows with timestamps when captions expose timing data. It uses multiple transcript sources, Apify proxy routing on cloud runs, streaming dataset writes, and per-video retries to improve reliability while keeping memory and compute cost low.

Main Use Cases

  • Build YouTube caption and subtitle datasets.
  • Summarize YouTube videos with LLMs.
  • Analyze podcasts, webinars, interviews, courses, and creator content.
  • Extract quotes, timestamps, and text segments for articles or clips.
  • Feed transcript segments into search, vector databases, or RAG workflows.
  • Monitor YouTube videos for brand, product, topic, or keyword mentions.

What Data You Get

Each dataset item is one transcript segment. A single video can produce many rows.

FieldDescription
video_idYouTube video ID.
urlCanonical YouTube watch URL.
titleVideo title when metadata is enabled and available.
channel_nameChannel name when metadata is enabled and available.
statusfound or missing.
languageTranscript language code.
sourceTranscript source that returned the result.
transcript_urlSource transcript URL when available. Signed source URLs can expire.
piece_indexSegment number within the transcript.
piece_countTotal segment count for the video.
piece_startSegment start time in seconds, when available.
piece_durSegment duration in seconds, when available.
textTranscript segment text.
word_countWord count for this segment.
transcript_word_countWord count for the full transcript.
errorError code when a transcript is missing.

The key-value store record OUTPUT contains totals, warnings, source timing summaries, billing details, and whether streaming output was enabled.

Input

FieldRequiredDescription
videoUrlsYesYouTube watch URLs, Shorts URLs, youtu.be links, or raw video IDs.
preferredLanguagesNoLanguage codes to prioritize, such as en, en-us, or es.
maxCharsNoMaximum normalized transcript characters per video.
maxVideoRuntimeSecsNoPer-video fallback budget from 30 to 240 seconds. Keep the 60-second default for short runs; higher values may require increasing the Actor run timeout.
exportVideoTextNoSave one JSON text document per successfully delivered unique video; off by default.
fetchVideoMetaNoAdds available title and channel metadata. Leave off for lowest cost.
useResidentialProxyNoOpt into paid residential proxy traffic for difficult or blocked videos. It is off by default; normal runs use Apify's automatic datacenter proxy routing.
youtubeCookiesNoOptional cookie string or Netscape cookie file content for stricter bot-check cases. Most runs do not need this.

Example input:

{
"videoUrls": [
"https://www.youtube.com/watch?v=dQw4w9WgXcQ"
],
"preferredLanguages": ["en", "en-us"],
"maxChars": 1000,
"maxVideoRuntimeSecs": 60,
"fetchVideoMeta": false,
"useResidentialProxy": false
}

Example Output

{
"video_id": "dQw4w9WgXcQ",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"status": "found",
"language": "en",
"source": "youtubei_player_api",
"record_type": "transcript_piece",
"piece_index": 2,
"piece_count": 61,
"piece_start": 18.64,
"piece_dur": 3.24,
"text": "Transcript segment text appears here.",
"word_count": 5,
"transcript_word_count": 487,
"error": ""
}

How To Run On Apify

  1. Open the Actor in Apify Console.
  2. Add one or more YouTube URLs or video IDs.
  3. Keep fetchVideoMeta off for transcript-only runs.
  4. Run the Actor.
  5. Open the Dataset tab to preview, filter, or export transcript rows.

Exporting Results

Download results from the Dataset tab as JSON, JSONL, CSV, Excel, XML, or RSS. API users can read rows from the run's defaultDatasetId.

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("thescrapelab/Apify-YouTube-Transcript-Scraper-2-0").call(
run_input={
"videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
"preferredLanguages": ["en", "en-us"],
"maxChars": 1000,
"maxVideoRuntimeSecs": 60,
"fetchVideoMeta": False,
}
)
if run is None:
raise RuntimeError("Actor call returned no run or storage metadata")
items = client.dataset((run["defaultDatasetId"] if isinstance(run, dict) else run.default_dataset_id)).list_items(clean=True).items
for item in items[:5]:
print(item["video_id"], item["piece_start"], item["text"])

Limits And Caveats

  • Transcripts depend on caption/subtitle availability for each video.
  • Private, removed, region-restricted, age-restricted, live, or bot-check-protected videos may return missing rows.
  • Metadata fetching adds extra requests and can increase runtime and proxy cost.
  • Duplicate input videos are not re-scraped, but duplicate rows are still returned for compatibility.
  • Work stops early enough to flush dataset and OUTPUT records before the configured Actor timeout. Unstarted videos receive a missing-status row.
  • transcript_url can be a signed source URL and may expire; use the returned text as the durable transcript value.
  • The Actor does not use the official YouTube Data API.

Pricing

The current Store price appears before each run. The Actor charges the video-transcript event once per successful unique video, even when that video produces many timestamped segment rows. Missing videos and duplicate copies are not charged as additional successful videos.

Cost-optimized settings:

  • Memory: 256 MB
  • Timeout: 120-240 seconds, depending on batch size
  • Processing mode: bounded internal parallel processing with streaming dataset writes

Start with one public video and keep maxChars bounded. Larger batches, cookie-assisted retrieval, and long transcripts can increase runtime and output volume.

Troubleshooting

ProblemWhat to try
No transcript foundConfirm the video has captions or subtitles available.
Run is slowKeep fetchVideoMeta disabled and split very large video lists into smaller batches.
A row reports video_runtime_budget_exhaustedIncrease maxVideoRuntimeSecs for that input, up to 240 seconds, or retry the video with residential proxy enabled.
A row reports actor_runtime_budget_exhaustedIncrease the Actor run timeout or submit a smaller batch. The Actor stopped starting work so it could save results cleanly.
Some videos are missingTry preferred language fallbacks such as ["en", "en-us", "es"].
Bot-check errorsProvide youtubeCookies only if the target videos require authenticated access.
Unexpected duplicate rowsRemove duplicate video URLs from input if you only want one copy of each transcript.

FAQ

Can this Actor scrape YouTube transcripts without a YouTube API key?

Yes. It extracts captions and transcript data from public web transcript sources and does not require a YouTube Data API key.

Does it work with YouTube Shorts?

Yes. You can provide Shorts URLs, watch URLs, youtu.be links, or raw video IDs.

Why does one video return many dataset rows?

The Actor returns timestamped transcript segments. This makes filtering, search, and downstream AI processing easier than a single large text blob.

Can I get one row per video?

The primary dataset stays segment-based. Set exportVideoText: true to also get one JSON text document per successfully delivered unique video. Read the transcriptExports manifest in OUTPUT for its record key.

What is the best low-cost setting?

Use 128 MB and keep fetchVideoMeta off unless title and channel metadata are required.

One text document per video for research and AI workflows

Set exportVideoText: true when you want text ready for downstream research, summarization or retrieval without grouping segment rows yourself. This does not call an AI model or fetch the video again.

Each successful unique video gets a JSON key-value record named TRANSCRIPT-<video_id> with video_id, canonical url, language, source, text and piece_count. Text is the delivered segments joined in timestamped piece order and remains bounded by your existing maxChars setting. The 1,000-character default is a preview and may omit later speech; increase it explicitly if you need more available caption text.

The OUTPUT record includes transcriptExports, a list of { "video_id": "...", "recordKey": "TRANSCRIPT-..." } entries. Open those records through the run's key-value store, or use the API:

# Reuse the client and run from the API example above, adding
# "exportVideoText": True to that call's run_input.
store = client.key_value_store(run["defaultKeyValueStoreId"])
output_record = store.get_record("OUTPUT")
output = output_record["value"] if output_record else {}
for entry in output.get("transcriptExports", []):
document = store.get_record(entry["recordKey"])["value"]
print(document["video_id"], document["text"])

The default dataset, timestamps and successful-video charge stay the same. Duplicate input videos share one text export, while their existing duplicate dataset rows are preserved. Missing or charge-suppressed transcripts have no text document. An export-write failure appears in OUTPUT.warnings; already delivered dataset segments remain available. Extra key-value storage operations can incur normal platform usage.