Tapeclerk · Catalogue sheet 1 · Podcast transcriptionPrinted 2026-09 · How we do it is sheet 2
- 00:00:04HostSo walk me through how a typical session starts for you.
- 00:00:09GuestUsually coffee first, then we just talk for a while.
- 00:00:15HostAnd you record the whole thing from the top?
- 00:00:19GuestEvery minute. You never know where the useful part is hiding.
- 00:00:28HostFair enough. Most people edit far too eagerly.
- 00:00:33GuestRight. Keep the messy middle, tidy it in the end.
Fig. 1Transport, seen from the operator's side. Supply reel left, take-up right; the tape passes the heads at 9.5 cm/s, and each line is printed as it does. The dialogue is sample text; the verbatim model output is Fig. 3.
Transcription · Apple Podcasts, Spotify, RSS, YouTube, direct file
Podcast episodes, transcribed verbatim.
Tapeclerk is podcast transcription for people who publish audio. Paste an Apple Podcasts, Spotify, RSS or YouTube link, or a direct audio file. Tapeclerk finds the episode's own audio, transcribes it with NVIDIA's Parakeet model on our own GPU, and returns a timestamped transcript with speaker turns, chapter marks and show notes.
What you get when a podcast episode is transcribed
Five things, on every transcript, in every format. The limits below are the ones enforced in code.
Podcast transcription turns the audio of an episode into text that keeps the timing, so it can be searched, quoted, captioned and linked to the second. Every transcript Tapeclerk returns carries the same five things:
- Segments with timecodes: start and end offset of every spoken passage, to the millisecond, in the order they were spoken.
- Speaker turns: who is talking, so an interview reads as one.
- Chapter marks: the passage boundaries an editor would cut, at the timecodes a player can jump to.
- Show notes with verbatim quotes: lines lifted out of the transcript word for word, never rewritten.
- The same output in five formats: JSON, plain text, SRT, VTT and Markdown, from one set of segments.
- Accepted links
- Apple Podcasts episode and show links, Spotify episode and show links, an RSS feed URL, a YouTube video link, or a direct
.mp3/.m4a/.wavfile. - Audio handling
- Whatever the publisher serves is decoded and resampled to 16 kHz mono PCM before the model sees it, so the model always gets the same input format. Downloads are capped at 400 MB and stopped mid-stream at the cap, not after it.
- Engine
- NVIDIA Parakeet TDT 0.6B v3 for the words, with Silero voice-activity detection, and a pyannote segmentation model with TitaNet speaker embeddings for who said them, all through sherpa-onnx on our own GPU. No third-party speech API is in the request path.
- Languages
- Whichever language the loaded model is for. If the audio comes back in a language that model is not configured for, the answer is
LANG_UNSUPPORTEDrather than a transcript in the wrong language. - Episode limits
- 4 hours of audio per episode. Longer recordings are split into parts and the transcripts stitch back in order.
- Cost
- One credit per 30 minutes of audio, rounded up: a 63-minute episode costs 3 credits. A run that does not produce a transcript costs nothing. A new account starts with 6 credits.
- Retention
- The fetched audio is deleted by the step that writes the transcript. Nothing is used to train a model.
A transcript, written top to bottom
This is the interface a job shows: the wire code first, then the lines as they are written, then the count and the stamp when it files. Until you paste a link above, the dialogue is sample text; a real job replaces it here. The verbatim model output of the test clip is Fig. 3.
- 00:00:12HostWelcome back. Today: how sound gets folded into memory.
- 00:00:26GuestNobody warns you that it is the voice you remember, not the words.
- 00:00:41HostSo a stranger reading a book you loved at nine,
- 00:00:52Guestbecomes that book. Ten years on, you hear the tape and you are nine again.
- 00:01:14HostIs that nostalgia, or is it a retrieval cue?
- 00:01:29GuestBoth. The experiment that separates them is messy, and I will get to it.
- 00:01:58GuestThey played people a clip and tested recall with the air-conditioning still running.
- 00:02:16HostAnd the hum helped.
- 00:02:21GuestThe hum helped a lot. The room is part of the memory.
- 00:02:47HostWhich is why we keep the timecodes with the transcript.
- 00:03:05GuestSo you can go back to the exact second.
Fig. 2The printout. Wire code, then lines as they are written, then the count, the stamp and the downloads when the job files.
Real output, verbatim
This is the output of the live engine on 45 seconds of the Hard Fork episode used to test the resolver, from 11:02 in, produced by the commands underneath it. Nothing has been edited.
- 00:11:02,160Speaker 1YouTube will agree to Meta's terms that Meta will reduce the daily limit for Facebook and Instagram to one hour and to expand nightmote hours to 10 p.m. to 7 a.m., which will be up from midnight to 6 a.m.
- 00:11:17,840Speaker 1So Meta is basically saying, like, look, it would be a real shame if something happened to the children of this country. But you have a way out. Simply agree to our terms, and then we will expand these hours. It's a really
- 00:11:30,560Speaker 2interesting bit of like game theory now. Like if you're TikTok or YouTube and you're looking at this, I imagine that you are saying, Well, obviously, we're not going to like join you in your like, you know, your court mandated or settlement mandated changes because unlike you, we are.
parakeet-tdt-0.6b-v3 · pyannote segmentation 3.0 + TitaNet · 2 speakers · 3 segments · 133 words · monotonic offsets 662 160 → 706 969 ms
Fig. 3Verbatim output of the live engine, as returned. "nightmote" is what the model heard for "night mode"; the last line stops where the clip ran out.
ffmpeg -ss 00:11:02 -t 45 -i episode.mp3 -ac 1 -ar 16000 clip16.wav
sherpa-onnx-offline --model-type=nemo_transducer --encoder=parakeet/encoder.onnx \
--decoder=parakeet/decoder.onnx --joiner=parakeet/joiner.onnx \
--tokens=parakeet/tokens.txt clip16.wav
sherpa-onnx-offline-speaker-diarization --clustering.num-clusters=2 \
--segmentation.pyannote-model=pyannote/model.onnx \
--embedding.model=titanet_small.onnx clip16.wav
Two things to note. "nightmote" is left as the model wrote it; a corrected transcript would hide the error. The change of speaker at 11:30 lands a word late, because the diarizer's boundaries sit a few hundred milliseconds off the real ones, so check the turns before you publish.
How the podcast transcription works
Three steps, in the same order for every link. The schematic shows the path a job takes.
-
Resolve: what kind of link is this?
An Apple episode link is not an audio URL, and neither is a Spotify one. Tapeclerk classifies the link first, then goes and gets the episode's own enclosure: for Apple, the title, show and duration come off the episode page's JSON-LD, the show's feed comes from the iTunes lookup API, and the audio comes from the RSS item whose title, duration and publish date match the episode. An RSS or mp3 link skips all of that and is used as given.
-
Fetch: audio and metadata
The enclosure is streamed, not buffered, with a byte cap that stops the request mid-stream rather than after the fact. Requests identify themselves as a browser where a platform requires it, follow a bounded number of redirects, and cache feed metadata for 15 minutes. Anything that answers 401 or 403 is reported as
AUTH_REQUIREDand not retried. -
Transcribe: speakers, chapters, timecodes
Audio is decoded to 16 kHz mono, cut at the pauses Silero finds into windows under a minute, and decoded by Parakeet on the GPU with a time on every token. A separate speaker pipeline draws who spoke when, and each word takes the speaker whose region covers it. The segments come out with the offsets the models reported; the render step is what turns them into JSON, text, SRT, VTT and Markdown.
Fig. 4The tape path. The moving dash is the tape. The diamonds on the ruler are chapters, the same marks the transcript carries at the same timecodes, which is what lets a player jump to them.
Podcast transcript formats, and which one you want
Five renderings of the same segments, from one set of timings, so the SRT and the VTT from a run always agree.
| Format | Shape | Use it for |
|---|---|---|
| .json | Segments, offsets in ms, speaker, language, duration | The source of truth: your app, your site, a search index, an LLM context window. |
| .txt | One line per segment, plain text | Reading, diffing, grep, pasting into a doc. |
| .srt | Index, 00:00:04,800 --> timestamps, comma milliseconds | Video editors and caption tools; burned-in subtitles. |
| .vtt | WEBVTT header, dot milliseconds, cue styling | The <track> element of a web player, YouTube uploads. |
| .md | Headings per chapter, speaker in bold, timecode anchors | Publication: an episode page, a newsletter, an archive. |
SRT or VTT for a podcast?
SRT if a human is going to open it in an editor, VTT if a browser is going to load it. SRT is the oldest and most widely imported caption format: index, timing line, two lines of text, blank line. VTT is its successor for the web: a header line, a dot rather than a comma before the milliseconds, and cue settings such as position and styling, which SRT cannot express. If you publish the episode on a site with a <video> or <audio> element, VTT is the one the player will read.
Podcast transcription errors, named
Podcast links fail for specific reasons, so every failure has a code, a cause and a fix. The code on the left is the literal string the API returns and the page prints.
| Code | Why it happens | What you do |
|---|---|---|
| DRM_LOCKED | The only copy of this episode sits behind a subscriber paywall. | Paste the RSS or file URL you are entitled to, or skip the episode. |
| AMBIGUOUS_EPISODE | A show link, or a feed with two items that match on title, duration and date. | Pick one of the returned candidates; the response carries them. |
| METADATA_ONLY | You sent the show's page, which has no audio on it. | Open an episode and copy that link, or pick from the candidates. |
| BAD_LINK | No scheme, a host that does not resolve, or a redirect that loops. | Add https:// and check the link resolves in a browser. |
| NOT_FOUND | 404, 410, or an episode that is no longer in the show's feed. | Find the current episode link; old show pages go stale. |
| NO_AUDIO | The feed item exists and has no enclosure: a trailer, or a subscriber-only drop. | Nothing on your side; the publisher did not attach audio. |
| AUTH_REQUIRED | 401 or 403: a private feed, or a platform that dislikes the request. | Paste the direct file URL, or your own feed URL with credentials. |
| TOO_LONG | Above 4 hours of audio, or above 400 MB. | Split the recording; transcripts stitch back in order. |
| NO_MODEL | No speech model is loaded for this job. | Try again later; the fault is on our side. |
| LANG_UNSUPPORTED | The audio is in a language the loaded model is not for. | Request that language; nothing is guessed in the meantime. |
| RATE_LIMITED | Too many runs from one key inside the window. | Back off and retry; the response carries when to come back. |
| NO_CREDITS | The episode costs more credits than the account holds; nothing ran. | Write to us for more credits. Nothing was consumed to tell you this. |
| AUTH_REQUIRED (401) | No key and no session: the API and the form both need an account. | Sign in at /account, or send Authorization: Bearer with your key. |
No credits are charged for any of them. A run costs nothing unless a transcript came out of it.
Who the transcript is for
Four uses, each of which needs the timecodes.
Podcasters
Publish the transcript with the episode, pull clips with the timecodes attached, and cut the show notes from lines people said.
Content and SEO teams
Turn a back catalogue into indexable pages, with the wording kept verbatim so quotations stay accurate.
Developers
One call per link, JSON back. Failures arrive as named codes rather than message strings to pattern-match.
Accessibility and archives
Captions in VTT for the player, a text record for the archive, and speaker turns kept.
The API in one request
One request starts a job and returns its status URL. The form at the top of this sheet uses the same endpoint, and it answers with the codes in the table above.
curl -X POST https://tapeclerk.com/api/v1/transcriptions \
-H "authorization: Bearer tc_live_…" -H "content-type: application/json" \
-d '{"url":"https://podcasts.apple.com/us/podcast/id1528594034?i=1000786488728","speakers":2}'
HTTP/1.1 202 Accepted
{"job_id":"tc_pfuW21mY9BbIFGiKgA83fQ","code":"RESOLVED","status":"queued",
"episode":{"show":"Hard Fork","title":"Meta Shifts the Blame …","duration_s":3776},
"credits_cost":3,"status_url":"/api/v1/jobs/tc_pfuW21mY9BbIFGiKgA83fQ"}
The key comes with an account; the form at the top of this sheet uses your signed-in session instead. New accounts start with 6 credits, enough for three hours of audio; write to us for more. Without a key or a session every endpoint answers 401 AUTH_REQUIRED, and a job the account cannot pay for is refused with 402 NO_CREDITS before anything runs. speakers is optional and is a floor, not a count: the diarizer groups the voices it hears, and the number only forces a count when it hears fewer. Ads, jingles and clips are voices too, so a two-host show usually files with more than two. You get a 202 and a job, not an estimate of how long the run takes. Poll the status URL: queued, fetching, transcribing, done, each stage with the time it was reached. When the job files, the transcript is at /api/v1/jobs/<id>/transcript/json, and the same segments as txt, srt, vtt and md. A run that files nothing costs nothing.
What happens to the audio
Deleted by the step that writes the transcript, not by a later cleanup job.
The fetched file is deleted by the same step that writes the transcript, in the same function, before the job reports done. The workspace has a byte cap, so a run cannot fill a disk on its way to being deleted. Audio is not used to train anything, and no speech API is in the path; the model runs on a machine we control.
The longer version, including which code deletes the file and how to check, is on sheet 2, how we do it.
Questions people ask
Eight questions, answered in the same words the rest of the sheet uses.
How do I transcribe a podcast episode from a link?
Paste the episode link. Tapeclerk accepts an Apple Podcasts episode or show link, a Spotify episode or show link, an RSS feed URL, or a direct .mp3, .m4a or .wav file. It resolves the link to the episode's own audio, fetches it, transcribes it and returns a timestamped transcript. There is nothing to upload.
Is podcast transcription accurate enough to publish?
The transcript is verbatim, with the timecodes the model reported, and it is labelled machine output rather than a human transcript. Check proper nouns and the boundaries where two speakers talk over each other before you publish. A transcript that silently corrects a name hides the error.
What is the difference between SRT and VTT subtitles?
SRT is plain text: an index number, a timestamp with a comma before the milliseconds, and the caption lines. VTT is WebVTT: a WEBVTT header, dot rather than comma before the milliseconds, and cue settings that carry styling and position. Both come out of the same segments here, so their timings never differ.
Does publishing transcripts help podcast SEO?
A transcript is how a search engine or an answer engine sees what was said in an episode. It gives the episode page text to rank on, gives a listener something to skim, and gives an answer engine a passage it can quote with a link. It does not raise rankings by itself; the transcript has to sit on an indexable page for the episode, not behind a player.
Can you transcribe an Apple Podcasts or Spotify link directly?
Yes. For Apple, metadata comes off the episode page's JSON-LD and the audio comes from the show's RSS enclosure, matched by title, duration and publish date. For Spotify it comes from the public oEmbed metadata and the show's feed. Where a platform does not expose playable audio, you get AMBIGUOUS_EPISODE or METADATA_ONLY with the candidates it could match, never a guess.
How long does it take to transcribe a one hour episode?
It depends on the length of the episode and what else is in the queue, so no fixed number is claimed. The job reports its progress and shows the first lines while the model is still writing.
Do you keep the audio after transcription?
No. The fetched audio is deleted as soon as the transcript is written, by the same step that produces it rather than a later cleanup job. Audio is never used to train a model.
What happens when a link cannot be transcribed?
One of a fixed set of codes: DRM_LOCKED, AMBIGUOUS_EPISODE, METADATA_ONLY, BAD_LINK, NOT_FOUND, NO_AUDIO, AUTH_REQUIRED, TOO_LONG, NO_MODEL, LANG_UNSUPPORTED, RATE_LIMITED, NO_CREDITS. Each arrives with a sentence a listener can read and the fix that goes with it, and none of them costs a credit.
Paste a link. Read the tape.
Apple Podcasts, Spotify, RSS, YouTube or a file. Speakers, timecodes, chapters and show notes, verbatim. The audio is deleted afterwards.