Guide

How to get YouTube transcripts in Python

Get YouTube transcripts in Python for one video, a whole channel or a search, handle long runs, then summarize them with Claude or GPT on the same API key.

Предоплата, без подпискиREST или MCPОдин ключ для моделей, данных и агентов

Эта страница ещё не переведена, поэтому показана на английском.

YouTubelovelyjsonitems[0]"video": "dQw4w9WgXcQ""lang": "en""start": 12.4"text": "…so the first thing…""start": 15.9"text": "…you want to do is…"

A YouTube transcript is the video's caption track as text: the lines people see as subtitles, each with a start time. Most videos have one, written by the uploader or generated automatically. This guide fetches transcripts from Python through a YouTube transcript API, one HTTP call per batch of videos, collects the video links for a whole channel or topic, and summarizes each transcript with a model on the same API key. For a single video, the free YouTube transcript generator needs no code.

01

How the transcript API works

The YouTube transcript tool takes a list of video links and returns one transcript per video. You call it like every other data tool: POST https://lovelyrouter.com/v1/tools/youtube-transcript/run with an input object and a max_results cap.

Input

startUrls is a list of youtube.com/watch?v=… or youtu.be/… links. lang is a caption language code such as en, es, de or pt-BR. Leave it empty for the video's default track.

Output

Each item has inputSource (the link you sent), id, selected (the track you got, for example English (auto-generated)) and transcript, a list of segments with text, startTime (like "0:18") and dur in seconds.

Billing

You pay per transcript returned. Starting a run holds its maximum cost, the per-result fee times max_results, and the run settles to what it delivered. A run that fails pays only for the transcripts it delivered first.

Most runs finish in 5 to 60 seconds. If one takes longer than the wait window (60 seconds by default), you get 202 and poll until it finishes, as Run a tool describes.

02

Get a transcript in Python

{}

You need an API key in LOVELY_API_KEY and requests. This helper starts a run, polls while it returns 202, and gives you the items:

Python
import os
import requests

BASE = "https://lovelyrouter.com/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['LOVELY_API_KEY']}"}


def run_tool(tool, tool_input, max_results):
    res = requests.post(
        f"{BASE}/tools/{tool}/run",
        headers=HEADERS,
        json={"input": tool_input, "max_results": max_results},
        timeout=90,
    )
    run = res.json()
    if not res.ok:
        raise RuntimeError(run["error"]["message"])

    # 202 = still running: poll, letting the server wait up to 60 s per request.
    while res.status_code == 202:
        res = requests.get(f"{BASE}/tools/runs/{run['id']}", headers=HEADERS, params={"wait": 60}, timeout=90)
        res.raise_for_status()
        run = res.json()

    print(f"{tool}: {run['status']}, {run['results']} results, charged {run['charge_usd']} USD")
    if run["error"]:
        print("  error:", run["error"])
    return run["items"] or []


items = run_tool(
    "youtube-transcript",
    {"startUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"], "lang": "en"},
    max_results=1,
)
video = items[0]
print(video["selected"]["title"])
for seg in video["transcript"][:5]:
    print(seg["startTime"], seg["text"])

A 200 means the run finished, not that it succeeded, so the helper prints status and error. On failed or timed_out, items still holds what the run delivered.

03

Transcripts for a whole channel or topic

{}

To cover a channel, list its videos with YouTube channel videos, then send the links to the transcript tool. For a topic, YouTube search does the same from keywords. Both return items with url, title, duration in seconds and publishDate.

Python
# Up to 30 videos from a channel (a handle, or a channel URL in startUrls).
videos = run_tool("youtube-channel", {"youtubeHandles": ["@MrBeast"]}, max_results=30)

# Or long videos about a topic uploaded this year.
# videos = run_tool("youtube-search", {"keywords": ["espresso tutorial"], "duration": "l", "uploadDate": "y"}, max_results=30)

urls = [v["url"] for v in videos if "/watch?v=" in v.get("url", "")]


def transcripts(urls, lang="en"):
    out = []
    for i in range(0, len(urls), 50):  # the tool takes up to 50 links per run
        batch = urls[i : i + 50]
        out += run_tool("youtube-transcript", {"startUrls": batch, "lang": lang}, max_results=len(batch))
    return out


found = transcripts(urls)
missing = set(urls) - {t["inputSource"] for t in found if t.get("transcript")}
print(f"{len(urls) - len(missing)} transcripts, {len(missing)} videos without one")

max_results caps each tool's own count field, so you don't need to set maxItems as well. Keep the link filter: the transcript tool doesn't take Shorts, live or playlist links. To start from a playlist, pass its URL to youtube-search in startUrls and use the video links it returns.

04

Summarize transcripts with a model

The same key calls Claude, GPT and Gemini. Point the Anthropic SDK at https://lovelyrouter.com and send the transcript with its timestamps, so the summary can say where each point is made:

Python
import anthropic

llm = anthropic.Anthropic(base_url="https://lovelyrouter.com", api_key=os.environ["LOVELY_API_KEY"])


def summarize(item):
    text = "\n".join(f"[{s['startTime']}] {s['text']}" for s in item["transcript"])
    message = llm.messages.create(
        model="claude-haiku-5.5",
        max_tokens=1024,
        messages=[{
            "role": "user",
            "content": "Summarize this video transcript in five bullet points. "
                       "Start each bullet with the timestamp where the point is made.\n\n" + text,
        }],
    )
    return message.content[0].text


for item in found:
    if item.get("transcript"):
        print(item["inputSource"])
        print(summarize(item), "\n")

claude-haiku-5.5 keeps batch summaries cheap; switch to claude-sonnet-5.5 for dense technical talks. With the OpenAI SDK, set base_url="https://lovelyrouter.com/v1" and call client.chat.completions.create(model="gpt-6.1-sol", …). Every text model accepts Chat Completions, so you can switch vendors by changing the model id. See Anthropic Messages for streaming and long outputs.

05

What it costs

A job like the one above has three parts: the per-video fee for listing the channel or search, the per-transcript fee for each transcript, and the model's tokens. The transcript is the prompt, so input tokens grow with video length. Today's prices:

МодельКонтекстВходВыводЧтение кеша
Claude Fable 5.1
claude-fable-5.1
1M$10.00$50.00$0.25
Claude Opus 5.5
claude-opus-5.5
1M$4.00$20.00$0.20
Claude Sonnet 5.5
claude-sonnet-5.5
1M$2.00$10.00$0.10
Claude Haiku 5.5
claude-haiku-5.5
1M$0.10$0.50$0.01
Claude Fable 5
claude-fable-5
1M$10.00$50.00$1.00
Claude Opus 5
claude-opus-5
1M$5.00$25.00$0.50
Claude Sonnet 5
claude-sonnet-5
1M$2.00$10.00$0.20
Claude Opus 4.8
claude-opus-4.8
1M$5.00$25.00$0.50
Claude Opus 4.7
claude-opus-4.7
1M$5.00$25.00$0.50
Claude Opus 4.6
claude-opus-4.6
1M$5.00$25.00$0.50
Claude Sonnet 4.6
claude-sonnet-4.6
1M$3.00$15.00$0.30
Claude Opus 4.5
claude-opus-4.5
200K$5.00$25.00$0.50
Claude Sonnet 4.5
claude-sonnet-4.5
1M$3.00$15.00$0.30
Claude Haiku 4.5
claude-haiku-4.5
200K$1.00$5.00$0.10

USD за 1 млн токенов, актуальные данные из каталога.

Everything comes out of one prepaid balance, with no subscription. The pricing page lists every tool and model.

06

Pitfalls

Videos without captions

A video with captions turned off has no track to read. Check transcript on every item and compare inputSource with the links you sent, as the missing set above does.

The wrong language

lang asks for a track; auto-generated captions count. When a video has no track in that language, check selected.languageCode before you trust the text. A model can translate while it summarizes, so you can ask for the default track and summarize in English.

Batches that get cut

A run takes up to 50 links. A list longer than max_results is cut to max_results entries, so set max_results to the batch length.

Too many runs at once

Your account can have 10 runs in progress. An 11th returns 429; start it again when one finishes.

Timestamps are strings

startTime is a clock string like "3:26" and dur is seconds as a string, like "5.039". Convert them before you do arithmetic.

07

Frequently asked questions

?
Can I get a transcript of a YouTube video that has no captions?+

No. The tool reads the video's caption tracks, including auto-generated ones. When a video has no caption track, there is no transcript to return, so check each item before you use it.

How do I get transcripts for every video on a channel?+

List the channel's videos with the youtube-channel tool, keep the watch links, and send them to the youtube-transcript tool in batches of up to 50 links per run.

Can I choose the transcript language?+

Yes. Set lang to a caption language code such as en, es or pt-BR, and auto-generated captions count. Leave it empty to get the video's default track, and read selected to see which track you got.

Do I need a separate API key for the model that summarizes?+

No. The key that runs the transcript tool also calls Claude, GPT and Gemini, and both come out of the same prepaid balance. Point the Anthropic SDK at the base URL, or the OpenAI SDK at the base URL with /v1.

Can an AI agent fetch transcripts on its own?+

Yes. Connect the MCP server to Claude Code, Cursor or another MCP client, and the agent can run the youtube-transcript tool with run_tool and read the results itself.

Next, see the other YouTube tools, the research agents use case for combining transcripts with web search, and the MCP server to let an agent do all of this from a prompt.

Один предоплаченный ключ для моделей, данных и агентов

Без подписки. Пополняйте баланс, используйте сколько нужно и смотрите каждое списание в логах.