The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the TranscriptFetch listing page.
Official, typed Python client for the TranscriptFetch API: fetch transcripts as clean, structured data, plus channel, playlist and search listings across YouTube, TikTok and Instagram. Sync + async, fully type-hinted.
Transcripts come from YouTube, TikTok, Instagram, or a direct media file URL (mp3/mp4/wav and friends). Channel and playlist take a URL from any of those platforms and detect it; search is YouTube by default, or any of them via platform=.
Every transcript carries the same metadata whichever platform served it:
video_id, url, platform, title, channel (the creator), duration in
seconds, language, thumbnail_url and source ("captions" or "audio").
A value the API could not determine is None, never missing.
Get an API key (50 free credits) at https://transcriptfetch.com/app. One credit per successful fetch; failed/blocked/no-transcript requests are free.
video and batch take a YouTube, TikTok or Instagram URL, a direct media file URL, or a bare YouTube ID. channel/playlist take a YouTube, TikTok or Instagram URL (or a YouTube @handle / PL… id) and detect the platform from it. search searches YouTube unless you pass platform:
When a source has no captions, the API transcribes its audio and answers with a job instead of a transcript. That comes back as a Transcript with status == "processing" and a job_id; poll it for free until it completes.
Batch works the same way by default (mode="auto"): entries with no caption track are transcribed from audio, come back with outcome == "processing" and a job_id, cost nothing on that call, and are charged on delivery at the audio rate. Re-send the same batch once the jobs have had time to finish and the text comes back normally — or poll each job_id with tf.transcripts.job(). Pass mode="captions" to read existing caption tracks only, in which case a captionless video fails as outcome == "error" with error.code == "no_captions" (and error.retry_with naming the audio mode):
List endpoints are cursor-paginated. Iterate every result without managing cursors:
Or page manually via page.next_cursor and the cursor= argument.
All errors subclass TranscriptFetchError. API errors carry .status, .code, .number (the thousands digit is the family; 5xxx means retry), .message, .docs, .retry_with (the request change that would succeed, when there is one), .details, .request_id, and a .retryable property:
429 (honoring Retry-After) and 5xx, with exponential backoff + jitter (max_retries=2 by default).Idempotency-Key so a retried request is never double-charged. Override per call with idempotency_key=....TranscriptFetch(api_key=..., base_url=..., timeout=30, max_retries=2). Both clients are context managers and accept a custom http_client= (httpx).Tests are fully mocked (no network). MIT licensed.