YouTube Transcript API for RAG: Cite the Exact Moment
Batch a whole YouTube channel's timestamped transcripts into your vector store in one run, so your RAG agent cites the exact video moment it answered from.

Batch a whole YouTube channel into your RAG store from one run, keep each chunk's timestamp as metadata, and your agent can answer questions with a link straight to the second the speaker said it. The trick is to treat timestamps as citations, not decoration: a chunk tagged with video_id and a start time becomes a watch?v=...&t=NNNs deep link in the answer, and one channel_url run replaces the N separate per-video calls you would otherwise loop.
Monid is a pay-per-call data API marketplace that reaches hundreds of external data endpoints from one key and one wallet, and you pay only when a run succeeds. This post is a build recipe: pick a channel, pull its recent uploads with timestamped transcripts in a single run, chunk on the timestamps, embed, store, then query with citations. Follow the steps in order and you will have a citeable knowledge base by the end.
TL;DR
- One
channel_urlrun on the Apifystarvibe/youtube-video-transcriptactor returns timestamped transcript segments plus metadata for a channel's recent uploads, so you skip looping one call per video. - Chunk on the transcript segments, not on character counts, and carry
video_idand the segment start time as metadata on every chunk. - At query time, retrieval hands back those two fields, and your prompt renders them as
https://www.youtube.com/watch?v=VIDEO_ID&t=NNNs. That is a real citation your reader can click. - The free scraping route breaks on IP blocks, returns no metadata, and cannot batch a channel. See the caveats below.
- Cost is per result, a fraction of a cent per video, so a channel's worth of transcripts lands in single-digit dollars. Magnitude only at monid.ai/tools.
Why not just call the official YouTube API?
Because it will not give you a transcript for a video you do not own. The YouTube Data API captions resource gates its download method behind the channel owner's OAuth, so pointing it at someone else's uploads returns an authorization error at every tier. For a RAG store built on other people's talks, the sanctioned door is closed before you start. A maintained scraper actor on Apify is the route that actually returns the words, and running it through Monid means no per-vendor signup and no OAuth consent screen.
Step 1: Pick a channel and a date window
Decide the scope before you spend anything. You want a channel whose recent uploads are the knowledge you plan to answer questions about, plus a start date that bounds "recent" for your use case. For a docs or research agent, the newest few dozen uploads since the start of the quarter is a sensible first pull. Note the channel handle URL (for example https://www.youtube.com/@taostats) and a start_date in ISO format. You will pass both in one run in Step 3.
Step 2: Set up Monid, then inspect the endpoint
For agents
Grab an API key at app.monid.ai, then paste this to your agent and hand it the key:
set up https://monid.ai/SKILL.md
It learns the whole discover, inspect, run workflow itself. More details in the agent quickstart.
For humans
npm install -g @monid-ai/cli
monid keys add --label main --key <your-api-key>
More details in the CLI quickstart.
Inspect first. This step is free and it shows you the full input schema and the exact per-result price before a single cent moves:
monid inspect -p apify -e /starvibe/youtube-video-transcript
Read the schema and confirm two things: the actor takes exactly one of youtube_url or channel_url, and include_transcript_text adds a plain concatenated transcript alongside the timestamped segments.
Step 3: Pull the channel in one run
Prove the shape on a single video first so you trust the timestamps against real playback:
# one video, plain-text transcript
monid run -p apify -e /starvibe/youtube-video-transcript \
-i '{"youtube_url":"https://www.youtube.com/watch?v=gN07gbipMoY","include_transcript_text":true}' -w
The -w flag waits inline and hands you the result in the same call. When the segments line up with what you hear, switch to the channel form. This single run returns transcripts for the newest uploads since your date, and it is the call that replaces looping N times:
# a whole channel: newest 50 uploads since a date, transcripts included
monid run -p apify -e /starvibe/youtube-video-transcript \
-i '{"channel_url":"https://www.youtube.com/@taostats","max_videos":50,"start_date":"2026-01-01","include_transcript_text":true}' -w
max_videos accepts 1 to 200 and is your spend cap, since billing is per result. Add end_date to close the window, or language with an ISO 639-1 code to pin the caption language. Each returned record carries the timestamped segments, the optional concatenated text, and metadata: title, description, publishedAt, duration, view, like, and comment counts, and the available caption languages.

Step 4: Chunk on the timestamps, keep the source moment
Here is where most transcript pipelines throw away the value. Do not split the concatenated text on a fixed character count. Chunk on the transcript segments themselves, grouping a handful of consecutive segments into a window of roughly a paragraph. For each chunk you build, attach two fields as metadata:
video_id, taken from the record's metadata.start, the start time in seconds of the first segment in that chunk.
Those two fields are the whole point. They travel with the chunk into the vector store and come back at retrieval time, which is what lets an answer point at a moment instead of a whole video. Group segments until a window reaches your target token size, then start a new chunk at the next segment boundary so no chunk straddles an awkward mid-sentence cut.
Step 5: Embed and store
Run each chunk's text through your embedding model and upsert it into your vector store, carrying the video_id and start metadata on every vector. The concatenated transcript_text field is there when you would rather hand a full video to a long-context model in one block, but for retrieval you want the segment-windowed chunks, because a tight chunk retrieves more precisely than a whole transcript. Store the video title and publishedAt alongside too, so your agent can name and date its source.
Step 6: Answer with a citation back to the exact second
At query time your retriever returns the top chunks, each with its video_id and start. Instruct your generation prompt to render the source of every claim as a link built from those fields: https://www.youtube.com/watch?v=VIDEO_ID&t=NNNs. The reader clicks it and the YouTube player opens at that second. A summarizer gives an opinion; a RAG answer with a timecode link gives a receipt.

How do you keep the store fresh?
Re-run the same channel call with a later start_date set to the day after your last pull. The actor returns only uploads inside the new window, you chunk and embed those, and you upsert them into the same store. New uploads flow in, old vectors stay put, and you never re-pay for transcripts you already hold. A scheduled agent can run this loop unattended because Monid ships as an MCP server it can drive directly.
What breaks on the free scraping route?
The free path costs nothing until it costs you an afternoon. The common youtube-transcript-api library pulls a single transcript in a few lines, but a loop over a channel's worth of IDs from one server trips YouTube's per-IP rate limits, and cloud IP ranges get blocked fastest. It returns text only: no title, no publishedAt, no view counts, so the metadata your agent cites is simply absent. It has no channel-level batch, so you first need a second tool just to list a channel's video IDs. And when only auto-generated captions exist, you branch and handle the fallback by hand. The actor handles the batch, the fallback, and the metadata inside one billed call.
Approximate cost tally
| Step | Call | Bills? | Rough cost |
|---|---|---|---|
| Inspect the schema | monid inspect | No | Free |
| Spot-check one video | one youtube_url run | Yes | A fraction of a cent |
| Pull 50 uploads | one channel_url run, max_videos 50 | Yes | Single-digit dollars |
| Weekly refresh | one channel_url run, new start_date | Yes | A few cents for a handful of new videos |
Discovery and inspection are always free, only run bills, and the per-result price shows on the inspect step before anything moves. Live magnitude is at monid.ai/tools.
FAQ
How do timestamps become citations in a RAG answer?
You store the first segment's start time and the video_id as metadata on each chunk. Retrieval returns them, and your prompt renders them as watch?v=VIDEO_ID&t=NNNs, a link that opens the player at the exact second the chunk was spoken.
Does one run really replace many per-video calls?
Yes. Pass channel_url with max_videos and a start_date, and the single run returns transcripts for every upload in that window. You do not list video IDs first or loop one call per video.
How much does it cost to build the store? Per result, a fraction of a cent per video, so a 50-video channel lands in single-digit dollars and a weekly refresh is a few cents. Inspecting is free and the exact price is shown before you run. See monid.ai/tools.
Can an agent run the whole pipeline? Yes. Because Monid ships as an MCP server, you hand your agent the key, point it at the channel, and it inspects, runs the channel pull, chunks on the timestamps, and embeds, all through the same interface.


