← Back to blog

Build a RAG Pipeline with the YouTube Transcript API: Turn Videos Into Queryable Knowledge

Video is the largest untapped knowledge base on the internet. Every conference talk, tutorial, podcast, and product demo contains information that search engines index poorly and LLMs have never seen. Retrieval-Augmented Generation (RAG) is the answer — but only if you can get the content out of the video and into a form your vector database understands.

That's exactly what the FetchAPI YouTube Transcript API solves. With one HTTP GET request you get a clean, timestamped transcript of any YouTube video. In this tutorial you'll build a production-ready RAG pipeline that ingests YouTube videos and answers natural-language questions from them — the same architecture used by research copilots, support bots, and internal knowledge bases.

Why Transcripts Are the Perfect RAG Source

A transcript is the video's content in its purest form: no audio noise, no filler, no encoding issues. Compared to audio transcription with Whisper (slow, GPU-hungry, error-prone on low-quality audio), YouTube's own captions are already accurate, timestamped, and free. The Transcript API fetches them in milliseconds and returns clean JSON your pipeline can consume immediately.

The architecture we'll build:

YouTube URL → Transcript API → chunk → embed → vector DB
                                                    ↑
User question ──────────────────────────────────────┘
                                                    ↓
                                              LLM answer

Step 1: Fetch a Transcript

The YouTube Transcript API takes a video URL and returns the full transcript as timestamped segments:

curl -s "https://fetchapi.tech/v1/transcript?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ" | jq '.transcript[0:2]'

Response:

{
  "status": true,
  "transcript": [
    {"text": "We're no strangers to love", "start": 0.0, "duration": 3.5, "lang": "en"},
    {"text": "You know the rules and so do I", "start": 3.5, "duration": 2.8, "lang": "en"}
  ],
  "video_id": "dQw4w9WgXcQ",
  "title": "Rick Astley - Never Gonna Give You Up (Official Music Video)",
  "length_seconds": 212,
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
}

Each segment has text, start (seconds), duration, and lang. The start timestamps are gold for RAG: they let you cite exactly where in the video an answer came from.

Step 2: Chunk Intelligently

Raw transcript segments are too small to embed well — you want chunks of roughly 300–800 tokens with semantic boundaries. The timestamped structure lets you merge consecutive segments until you hit a target size, then start a new chunk. This is far more reliable than naive character splitting because segments are natural speech units.

Here's a simple, effective chunker:

def chunk_transcript(segments, max_chars=2000):
    chunks, current, start_time = [], [], None
    for seg in segments:
        if start_time is None:
            start_time = seg["start"]
        current.append(seg["text"])
        if sum(len(t) for t in current) >= max_chars:
            chunks.append({
                "text": " ".join(current),
                "start": start_time,
                "end": seg["start"] + seg["duration"],
            })
            current, start_time = [], None
    if current:
        chunks.append({"text": " ".join(current), "start": start_time, "end": segments[-1]["start"] + segments[-1]["duration"]})
    return chunks

For long videos, consider splitting on speaker or topic shifts — segment timestamps plus the transcript text give you everything you need for a semantic splitter later.

Step 3: Embed and Index

Embed each chunk with your favorite embedding model (OpenAI text-embedding-3-small, Cohere, or a local model like bge-small all work) and store the vectors in any vector database — pgvector, Qdrant, Chroma, or LanceDB. Store the chunk text, its timestamp range, the video ID, and the video title alongside the vector:

import requests, openai

transcript = requests.get(
    "https://fetchapi.tech/v1/transcript",
    params={"url": video_url},
).json()

chunks = chunk_transcript(transcript["transcript"])
vectors = openai.embeddings.create(
    model="text-embedding-3-small",
    input=[c["text"] for c in chunks],
)

for chunk, vec in zip(chunks, vectors.data):
    collection.upsert([{
        "id": f'{transcript["video_id"]}:{chunk["start"]}',
        "vector": vec.embedding,
        "payload": {
            "text": chunk["text"],
            "start": chunk["start"],
            "end": chunk["end"],
            "video_id": transcript["video_id"],
            "title": transcript["title"],
        },
    }])

Storing video_id and start in the payload is what makes citations possible — your LLM can answer and link to the exact minute of the video.

Step 4: Retrieve and Generate

At query time, embed the user's question, fetch the top-k nearest chunks, and stuff them into an LLM prompt:

q_vec = openai.embeddings.create(model="text-embedding-3-small", input=[question]).data[0].embedding
hits = collection.query(vector=q_vec, top_k=5)

context = "\n\n".join(
    f"[{h['payload']['title']} @ {h['payload']['start']//60}m{h['payload']['start']%60:02d}s]\n{h['payload']['text']}"
    for h in hits
)

answer = openai.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "system", "content": "Answer using only the provided video transcript excerpts. Cite timestamps."},
        {"role": "user", "content": f"Question: {question}\n\nExcerpts:\n{context}"},
    ],
)
print(answer.choices[0].message.content)

The result: a chatbot that has genuinely watched your video library and answers with timestamped citations.

Enrich with Markdownify and OGSnap

Transcripts are the core, but a video's description, pinned comment, and Open Graph metadata add crucial context. FetchAPI's Markdownify API turns the video's watch page — or any linked blog post — into clean markdown:

curl -s "https://fetchapi.tech/v1/markdownify?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ"

And OGSnap extracts title, description, and thumbnail in one call:

curl -s "https://fetchapi.tech/v1/ogsnap?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ"

Use OGSnap at ingestion time to populate the video's metadata fields, and Markdownify to pull in supplementary articles the video references — your RAG index becomes richer than the transcript alone.

Production Considerations

Putting It All Together

You now have a complete recipe: fetch with the Transcript API, chunk on timestamp boundaries, embed, index, retrieve, and answer with citations. The same pattern powers everything from meeting-note copilots to compliance search over earnings calls.

The FetchAPI YouTube Transcript API is free to start, needs no API key for basic use, and returns transcripts in a single request — the fastest way to turn the world's video knowledge into something your agents can actually query. Try it with a video from your own watch history, and you'll have a working RAG pipeline before lunch.