Feed YouTube Transcripts to GPT and Claude
David Boulen · 7/27/2026 · 8 min read
Feed YouTube Transcripts to GPT and Claude for Analysis
Getting a YouTube transcript into an LLM is straightforward. Getting useful, reliable output back requires a bit more care. The raw JSON the API returns is noisy, tokens are not free, and models can confabulate details that were never in the video. This guide covers every step from fetch to answer, with code you can run today.
Why Raw Transcript JSON Needs Cleaning First
When you call a transcript endpoint, you get back an array of segment objects. Each object carries the spoken text, a start time, and a duration. That structure is useful for subtitle rendering but wasteful for language models.
A typical response looks like this:
{
"transcript": [
{ "text": "so today we're going to talk about", "start": 0.0, "duration": 2.1 },
{ "text": "building RAG pipelines with open source tools", "start": 2.1, "duration": 3.4 }
]
}
Every start and duration value is a token the model has to read and ignore. For a 60-minute video, timestamp fields alone can add several thousand tokens of overhead with no benefit to summarization or Q&A tasks. That overhead pushes your actual content closer to the model's limit and increases cost on every call.
There is a second problem: filler. Auto-generated captions include false starts, repeated words, and partial sentences split across segments. Left uncleaned, these confuse the model and degrade output quality.
See From Transcript JSON to Clean Text: Parsing Tips for a deeper treatment of the parsing edge cases.
Stripping Timestamps and Normalizing Text
The cleaning step is a few lines of Python. Join the segment text, collapse whitespace, and drop anything that is not prose:
import re
def clean_transcript(segments: list[dict]) -> str:
# Join all segment text
raw = " ".join(seg["text"] for seg in segments)
# Collapse repeated whitespace
raw = re.sub(r"\s+", " ", raw)
# Remove common caption artifacts like [Music] or [Applause]
raw = re.sub(r"\[.*?\]", "", raw)
return raw.strip()
If you need to keep timestamps for citation purposes, store a parallel index instead of embedding them in the text you send to the model. Map character offsets or sentence indices back to the original segment list after the model responds.
def index_segments(segments: list[dict]) -> list[dict]:
"""Build a lookup: character_start -> (start_time, text)"""
index = []
cursor = 0
for seg in segments:
text = seg["text"].strip()
index.append({"char_start": cursor, "time": seg["start"], "text": text})
cursor += len(text) + 1
return index
This gives you grounding for citations without bloating the prompt.
Prompt Patterns for Common Tasks
Summarization
An answer-first system prompt outperforms vague instructions:
SUMMARIZE_PROMPT = """
You are a precise summarizer. The text below is a cleaned YouTube transcript.
Rules:
- Write a 3-5 sentence summary covering the main argument and key takeaways.
- Do not add information that is not in the transcript.
- If the transcript is unclear, say so rather than guessing.
Transcript:
{transcript}
"""
Q&A Extraction
For question-and-answer workflows, tell the model to pull only what it can support from the text:
QA_PROMPT = """
You are a strict Q&A extractor. Given the transcript below, generate up to 5 question-and-answer pairs.
Rules:
- Each answer must be directly supported by the transcript.
- Cite the approximate timestamp range in parentheses after each answer, e.g. (around 4:30).
- If you cannot find support for a question, do not include it.
Transcript:
{transcript}
"""
Topic Extraction
TOPICS_PROMPT = """
List the 5-7 distinct topics discussed in this transcript, ordered by how much time is spent on each.
Format: one topic per line, followed by a brief phrase describing it.
Transcript:
{transcript}
"""
Handling Context Windows with Chunking and Map-Reduce
Most LLM providers expose context windows measured in tokens. Claude Sonnet 4.5 supports 200,000 tokens; newer Claude models support up to 1 million tokens, according to Anthropic's context window documentation. Even a 1M-token window does not eliminate the need for chunking: longer inputs increase latency, cost, and the risk of the model losing focus on content buried in the middle.
A 60-minute video sits comfortably inside a 200K context window when the transcript is cleaned. But a full course, a podcast series, or a batch of multiple videos will not. That is where map-reduce comes in.
Map step: split the cleaned transcript into chunks, summarize each independently.
Reduce step: combine the partial summaries into a single final output.
import tiktoken
def chunk_text(text: str, max_tokens: int = 512, overlap: int = 50) -> list[str]:
enc = tiktoken.get_encoding("cl100k_base")
tokens = enc.encode(text)
chunks = []
start = 0
while start < len(tokens):
end = min(start + max_tokens, len(tokens))
chunk_tokens = tokens[start:end]
chunks.append(enc.decode(chunk_tokens))
start += max_tokens - overlap
return chunks
def map_reduce_summarize(chunks: list[str], client, model: str) -> str:
# Map: summarize each chunk
partial_summaries = []
for chunk in chunks:
resp = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": "Summarize the following transcript excerpt in 2-3 sentences."},
{"role": "user", "content": chunk}
]
)
partial_summaries.append(resp.choices[0].message.content)
# Reduce: combine partial summaries
combined = "\n\n".join(partial_summaries)
final = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": "Combine these partial summaries into one coherent summary."},
{"role": "user", "content": combined}
]
)
return final.choices[0].message.content
The trade-off is real: map-reduce costs more in API calls and can lose connections between ideas that span chunk boundaries. For single videos under 30 minutes, skip chunking and send the cleaned text directly.
Full Pipeline: Fetch, Clean, and Call the Model
Here is a complete Python pipeline using YouTube Transcriber and the OpenAI client. The same pattern works with Anthropic's SDK by swapping the client call.
import os
import re
import requests
import openai
TRANSCRIBER_KEY = os.environ["TRANSCRIBER_API_KEY"]
OPENAI_KEY = os.environ["OPENAI_API_KEY"]
def get_transcript(video_id: str) -> list[dict]:
url = "https://getyoutubetranscriber.com/api/v2/transcript"
headers = {"Authorization": f"Bearer {TRANSCRIBER_KEY}"}
params = {"video_url": video_id}
resp = requests.get(url, headers=headers, params=params)
resp.raise_for_status()
return resp.json()["transcript"]
def clean_transcript(segments: list[dict]) -> str:
raw = " ".join(seg["text"] for seg in segments)
raw = re.sub(r"\s+", " ", raw)
raw = re.sub(r"\[.*?\]", "", raw)
return raw.strip()
def summarize(text: str) -> str:
client = openai.OpenAI(api_key=OPENAI_KEY)
resp = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "system",
"content": (
"You are a precise summarizer. Summarize the transcript below in 4-5 sentences. "
"Do not add information not present in the transcript."
)
},
{"role": "user", "content": text}
]
)
return resp.choices[0].message.content
if __name__ == "__main__":
video_id = "dQw4w9WgXcQ"
segments = get_transcript(video_id)
clean = clean_transcript(segments)
print(f"Token estimate: ~{len(clean.split()) * 1.3:.0f}")
summary = summarize(clean)
print(summary)
To use Claude instead, swap the summarize function:
import anthropic
def summarize_claude(text: str) -> str:
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
msg = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
messages=[
{
"role": "user",
"content": (
"Summarize this YouTube transcript in 4-5 sentences. "
"Do not add information not present in the transcript.\n\n"
+ text
)
}
]
)
return msg.content[0].text
YouTube Transcriber handles the messy parts of transcript retrieval: IP rotation, anti-bot challenges, and caption format normalization across 125+ languages. That means your pipeline code stays focused on the LLM logic rather than YouTube reliability workarounds. For context on what those workarounds involve, see Handling YouTube Anti-Bot Challenges in Production.
Guardrails for Hallucinations and Timestamp Citations
Language models are confident even when they are wrong. With transcript-grounded tasks, two patterns reduce fabrication significantly.
Citation anchoring. After cleaning the transcript, preserve a mapping from sentence index to timestamp. Include this instruction in your system prompt:
After each factual claim, include the approximate video timestamp in brackets, e.g. [12:30].
Only cite timestamps that appear in the provided transcript index.
If you cannot find a timestamp for a claim, mark it as [unverified].
Then validate any bracketed timestamp in the output against your index before surfacing it to users.
Temperature and grounding. Set temperature to 0 or 0.1 for factual extraction tasks. Higher temperatures increase creativity but also increase confabulation. For summaries and Q&A, you want the model to stay close to the source material.
Source restriction. Add an explicit refusal clause to your system prompt:
Do not draw on any knowledge outside the provided transcript.
If the transcript does not contain an answer, say "not covered in this video."
This does not eliminate hallucination, but it gives the model a clear instruction to cite rather than invent. When you combine this with timestamp anchoring, users can click through to the video moment and verify the claim themselves.
For pipelines processing large volumes of videos, adding a retrieval layer means the model only sees the most relevant segments for each query rather than the entire transcript. This is the basis of retrieval-augmented generation (RAG) applied to video content, and it scales well to channel-level analysis.
Practical Gotchas
Auto-generated captions vary in quality. Transcripts for videos without manually added captions use speech recognition output, which can misrecognize technical terms, proper nouns, and accented speech. If accuracy matters, check whether manual captions are available before choosing which to process.
Token estimates are approximate. The ~{words * 1.3} heuristic in the pipeline above is a rough guide. Use the model provider's token counting API or the tiktoken library for accurate counts before you hit the context limit in production.
Caching saves money. If your application re-analyzes the same videos, cache the cleaned transcript text and the LLM output keyed on the video ID. A 60-minute video that is processed once and cached avoids dozens of redundant API calls as users query it.
Language matters. If the video is in a language other than English, confirm the model you are using has strong support for that language before building a production workflow around it. Both GPT-4o and Claude Sonnet handle most major languages well, but output quality varies.
Next Step
Start with the free tier: YouTube Transcriber gives you 100 credits with no credit card required, which is enough to run the pipeline above on a handful of videos and validate it against your actual use case. The API documentation covers authentication, the transcript endpoint, and the bulk request format.