If you’re building an AI agent, a search tool, or a RAG pipeline over podcast content, you need transcripts — and you probably assumed you’d have to run every episode through a speech-to-text model. Often, you don’t. A large and growing share of podcasts already publish transcripts themselves, right inside their RSS feed. The hard part isn’t transcription; it’s extracting and normalizing what’s already there.
Podcasts already ship transcripts
The Podcasting 2.0 namespace added a <podcast:transcript>
tag that publishers place in each episode’s RSS <item>. It
points to a transcript file with a URL and a MIME type:
<podcast:transcript
url="https://example.com/ep342/transcript.vtt"
type="text/vtt" />
That sounds simple until you look across real feeds. Publishers use JSON (the Podcasting 2.0 schema), WebVTT, SubRip (SRT), or plain text/HTML — and some list several formats or languages for the same episode.
Why parsing it yourself is tedious
To do this by hand for arbitrary shows, you end up writing and maintaining:
- A parser for each format — the JSON segment schema, VTT cue
timings with
<v Speaker>voice tags, SRT’s indexed blocks, and a plain-text fallback. - Timestamp handling for the different notations you’ll hit
(
HH:MM:SS.mmmvsMM:SS,mmm). - Selection logic when a feed lists multiple transcripts, plus fetching, retries, and graceful handling of dead or malformed source URLs.
That’s a lot of plumbing before you extract a single usable word.
PodKit normalizes all of it into one JSON response
PodKit reads the feed, picks the best available transcript
(JSON › VTT › SRT › text), fetches it, and parses it into one
consistent shape every time: a format, a flat text
string, and segments with startTime,
endTime, speaker, and text.
curl "https://podkitapp.com/v1/episode/42/transcript" \
-H "x-api-key: pk_your_key"
{
"episodeId": 42,
"format": "vtt",
"text": "Welcome back to the show. Today we're talking about AI agents...",
"segments": [
{ "startTime": 0.0, "endTime": 4.2, "speaker": "Host", "text": "Welcome back to the show." },
{ "startTime": 4.2, "endTime": 9.8, "speaker": "Guest", "text": "Thanks for having me." }
]
}
The {id} is a PodKit episode id — you get it from
GET /v1/podcast/{itunesId}, which lists a
show’s episodes. If a source file can’t be fetched or parsed, you still get a
clean 200 with text and segments set to
null, plus sourceUrl and parseError: true,
so you can fall back to the raw file. Episodes with no published transcript
return 404 — that’s the case where you’d reach for your own
speech-to-text.
Use text for embeddings, segments for citations
For RAG, embed the flat text (or chunk the segments).
For agents that cite sources, the segments give you timestamped,
speaker-attributed spans you can link back to the exact moment in the audio.
Because PodKit caches parsed transcripts, repeat reads are fast and don’t re-hit
the origin feed.