Apify Store
AS
Apify Store
/johnvc/YoutubeTranscripts

YouTube Transcript & Subtitles Scraper API

Scrape YouTube transcripts, subtitles, and captions in bulk, the cheapest pay-per-video YouTube transcript API on Apify. Callable from any MCP client (Claude, Cursor, ChatGPT). Supports YouTube videos, Shorts, and every URL format.

liveasyncunknown~30s typical
VIDEOSAIDEVELOPER_TOOLS
$0.0020
per result + $0.01 call
plus $0.001 platform fee per run
Usage-based actor: event charges passed through at cost plus 25%
Bring your own Apify Store key: provider portion drops to $0.
$Set up https://cracked-ai-pearl.vercel.app/SKILL.md, then use Cracked to run apify /johnvc/YoutubeTranscripts for me.

Input

FieldTypeDescription
youtube_urlanyRequired unless 'channel' is provided. Provide one YouTube URL as a string, or multiple as an array (max 250 URLs per run). Works with standard videos, Shorts, youtu.be short links, embed URLs, and m.youtube.com mobile URLs. Channel URLs (youtube.com/@handle, /channel/, /c/, /user/) are detected automatically and treated as the 'channel' input. Each video URL is processed in parallel. If more than 250 URLs are submitted, only the first 250 are processed and a truncation notice is written to the dataset - split larger batches into multiple runs. Invalid URLs are recorded as errors in the dataset but do not stop the run. Charged per video successfully transcribed.
languagesarrayOrdered list of ISO 639-1 language codes. The first available transcript matching one of these languages is returned. Example: ["en", "es", "fr"] tries English first, then Spanish, then French. Defaults to ["en"] when omitted. default ["en"]
translate_tostringOptional. If set to an ISO 639-1 code (e.g. "es", "fr", "de"), the picked transcript is translated to this language. Requires the source transcript to be translatable - run with list_only=true first to see translation_languages for each available transcript. If translation is unavailable, the original transcript is returned (no error).
transcript_typestring (any | manual | generated)Filter which transcript variant to consider when both manually-created and auto-generated captions exist for a language. "any" picks whichever matches the language priority first; "manual" only considers human-made captions; "generated" only considers auto-generated. default "any"
output_formatsarrayOptional list of extra output formats to include in the dataset alongside the default structured fields. Allowed values: "srt" (SubRip subtitles), "vtt" (WebVTT subtitles), "text" (plain text, newline-separated). Unknown values are ignored with a warning. The structured fields (timestamped, non_timestamped, etc.) are always included. default []
preserve_formattingbooleanIf true, keep YouTube's inline HTML formatting tags (<i>, <b>) in transcript text. Default false (strips them for clean text). default false
list_onlybooleanIf true, do NOT fetch any transcript. Instead, for each URL return the list of all available transcripts with their language code, generated/manual status, is_translatable flag, and translation_languages. Useful for discovering what languages exist before picking one. Not charged as a videoprocessed event. default false
include_metadatabooleanIf true, also fetch video metadata via yt-dlp: title, description, channel_name, channel_id, channel_url, view_count, like_count, video_duration_seconds, upload_date, thumbnail_url, tags, categories, availability, was_live. Adds about 1-3 seconds per video. If metadata extraction fails, the transcript is still returned and metadata_error is populated. Defaults to true. default true
channelanyOptional. One YouTube channel as a string, or multiple as an array. Accepts an @handle ("@mkbhd"), a bare handle ("mkbhd"), a channel ID ("UCBJycsmduvYEL83R_U4JriQ"), or any channel URL (/channel/, /c/, /user/, /@handle; a /videos, /shorts, or /streams tab URL keeps that tab). Each channel produces one dataset row per video, newest first, up to max_videos: video_id, url, title, duration, view count, and thumbnail. Rows are marked result_type="channel_video". Listing is not charged as a videoprocessed event.
max_videosintegerMaximum number of videos to list per channel, newest first. Default 100. Values above 1000 are capped at 1000 (and values below 1 are raised to 1) with a log warning rather than failing the run. When channel_transcripts is true, at most 250 videos per run (across all channels plus explicit URLs) proceed to transcript extraction. default 100
channel_transcriptsbooleanIf true, every video listed from the channel(s) is also queued for transcript extraction (newest first, deduplicated against youtube_url entries, subject to the 250 videos per run limit). Each successful transcript is charged as a videoprocessed event, exactly like videos passed via youtube_url. Default false: channels are only listed. default false

Call it

curl
curl https://cracked-ai-pearl.vercel.app/v1/run \
  -H "Authorization: Bearer ck_live_..." -H "content-type: application/json" \
  -d '{"provider":"apify","endpoint":"/johnvc/YoutubeTranscripts","input":{"languages":["en"],"transcript_type":"any","output_formats":[],"preserve_formatting":false,"list_only":false,"include_metadata":true,"max_videos":100,"channel_transcripts":false},"wait":false}'
poll
curl "https://cracked-ai-pearl.vercel.app/v1/runs/<runId>?wait=30" -H "Authorization: Bearer ck_live_..."
cli
npx cracked-ai run -p apify -e /johnvc/YoutubeTranscripts -i '{"languages":["en"],"transcript_type":"any","output_formats":[],"preserve_formatting":false,"list_only":false,"include_metadata":true,"max_videos":100,"channel_transcripts":false}' -w 120
mcp
run_tool({ provider: "apify", endpoint: "/johnvc/YoutubeTranscripts", input: {"languages":["en"],"transcript_type":"any","output_formats":[],"preserve_formatting":false,"list_only":false,"include_metadata":true,"max_videos":100,"channel_transcripts":false}, wait: false })

Try it

Runs against your signed-in workspace balance. Sign in if you have not.