GitHubLog in
SDKs & integrations

Python SDK

The official, typed Python client, sync + async. Fetch transcripts, channels, playlists, and search as structured data.

Official SDK. Source + issues on GitHub. Your key falls back to the TRANSCRIPTFETCH_API_KEY env var, keep it server-side. One credit per successful caption fetch (AI Fallback Transcription, on by default for videos without captions, bills per started 5 minutes of audio); failed/blocked/no-transcript requests are free.

Install

BASH
python -m pip install transcriptfetch-sdk==2.4.0

Examples target SDK 2.4.0, which requires Python 3.9+. Use a currently supported Python release for new projects.

Quickstart

Get an API key (50 free credits a month) at the dashboard, then:

PYTHON
from transcriptfetch import TranscriptFetch

# api_key falls back to the TRANSCRIPTFETCH_API_KEY env var
tf = TranscriptFetch(api_key="tf_live_...")

t = tf.transcripts.video("https://youtu.be/aircAruvnKk")
if t.status == "processing":
    print("Pending job:", t.job_id)  # poll with tf.transcripts.job(t.job_id)
else:
    print(t.title)
    for seg in t.segments:
        print(f"[{seg.start:.1f}] {seg.text}")
if t.usage is not None:
    print("credits left:", t.usage.balance)

The single-video HTTP response returns timestamped segments by default and omits text. The SDK represents missing text as None. Join segment text locally if you need both forms. Use timestamps=False for plain text:

PYTHON
transcript = tf.transcripts.video("aircAruvnKk", mode="captions", timestamps=False)
print(transcript.text)

This example explicitly requests captions only: a missing track raises an error instead of starting AI Fallback Transcription. The resource method returns a typed Transcript model.

Endpoints

video/channel/playlist accept URLs or raw IDs (normalized automatically).

PYTHON
tf.transcripts.video(video)                              # single transcript
tf.transcripts.channel(channel, limit=10, cursor=cursor)  # video metadata
tf.transcripts.playlist(playlist, limit=10, cursor=cursor)
tf.transcripts.search(query, limit=10, cursor=cursor)
tf.transcripts.batch(video_ids)                          # auto mode
tf.transcripts.batch(video_ids, mode="captions")          # no audio fallback
tf.transcripts.job(job_id)                               # poll an audio job
tf.health()                                             # unauthenticated probe

SDK 2.4.0 adds mode, timestamps, and callback_url options to video(), plus the tf.monitors resource. Channel since_video_id and YouTube listing filters (tab, sort, query, and search filters) still use the generic _request() method. It retains the SDK's retries, idempotency keys, and typed errors. Batch limits are 50 on free/Basic/Pro and 500 on Mega/Scale; inspect each result's outcome (ok, processing, or error) rather than treating the whole batch as delivered.

PYTHON
page = tf._request(
    "POST",
    "/api/v2/transcripts/channel",
    body={"channel": "@lexfridman", "tab": "shorts", "limit": 10},
    idempotent=True,
)["data"]

Monitors

SDK 2.4.0 supports the full monitor API, including sync and async clients. Creation starts scheduled checks for new videos. Every check, the initial baseline included, costs 1 credit; optional transcripts cost extra.

PYTHON
with TranscriptFetch(timeout=120) as tf:
    monitor = tf.monitors.create("@lexfridman", interval_minutes=60, transcripts=True)
    # Save monitor.webhook_secret securely: it is only returned on creation.
    current = tf.monitors.get(monitor.id)
    all_monitors = tf.monitors.list(since=current.last_event_id)
    for event in tf.monitors.iter_events(monitor.id, limit=10):
        print(event.type, event.data)
    tf.monitors.update(monitor.id, status="paused")
    # tf.monitors.check(monitor.id) checks now and may spend credits.
    # tf.monitors.delete(monitor.id) removes the monitor and its events.

Pass webhook_url to create() for push delivery, or use events() / iter_events() to read events. update(webhook_url=None) removes a webhook; omitted settings stay unchanged. check() can return error on a listing failure even with HTTP 200. Use await for the async client's methods and async for with its event iterator. See the monitor guide for signature verification and billing.

Long media and jobs

AI Fallback Transcription can return HTTP 202 with a job instead of a finished transcript. The SDK exposes status == "processing" and job_id; poll tf.transcripts.job(job_id) with a delay and a bounded deadline. Short media may finish inline. In Python SDK 2.4.0, a failed job envelope raises APIError, even when polling returns HTTP 200. To request a transcription webhook, pass callback_url to video(). The Python tutorial includes a complete polling example; the transcription guide covers the job contract and billing.

Pagination

List endpoints are cursor-paginated. Iterate every result without managing cursors:

PYTHON
# Iterate every result without managing cursors
for video in tf.transcripts.iter_channel("@lexfridman", limit=10):
    print(video.video_id, video.title)

# ...or page manually via page.next_cursor and the cursor= argument.

Async

PYTHON
import asyncio
from transcriptfetch import AsyncTranscriptFetch

async def main():
    async with AsyncTranscriptFetch() as tf:
        t = await tf.transcripts.video("aircAruvnKk")
        if t.status == "processing":
            print("Pending job:", t.job_id)  # await tf.transcripts.job(t.job_id)
        else:
            print(t.text if t.text is not None else " ".join(s.text for s in t.segments))
        async for v in tf.transcripts.iter_search("how transformers work", limit=10):
            print(v.title)

asyncio.run(main())

Errors

All errors subclass TranscriptFetchError. API errors carry .status, .code, .message, and .request_id.

PYTHON
from transcriptfetch import (
    AuthenticationError, InsufficientCreditsError, InvalidRequestError,
    RateLimitError, IdempotencyConflictError, UpstreamUnavailableError,
    InternalServerError, APIError, APIConnectionError, APITimeoutError,
)

try:
    tf.transcripts.video("bad")
except InsufficientCreditsError:
    ...                       # 402: top up at /pricing
except RateLimitError as e:
    print(e.retry_after)      # 429
except APIError as e:
    print(e.status, e.code, e.request_id)

Reliability built in. Automatic retries on 429 (honoring Retry-After) and 5xx with exponential backoff; every write auto-sends an Idempotency-Key so a retried request is never double-charged. Configure via TranscriptFetch(api_key=..., base_url=..., timeout=30, max_retries=2).

See the endpoint reference for every route and the response format.