Paste the stream, not the page. A station's real audio lives at an address ending in .mp3, .aac or .m3u8, and once a live transcription has it, nobody needs to be listening.
A newsroom that monitors three radio stations, two television streams and a handful of YouTube lives has a staffing problem before it has a transcription problem. Somebody has to be listening, and somebody has to press record. A live transcription with a stream as its source takes over both jobs: give it the address of the stream and the server opens it, decodes it and transcribes it as it airs, so nobody has to be at a desk when a press conference starts early. The hard part, it turns out, is finding the address.
A live transcription can take its audio from a stream the server pulls itself: an internet radio station, an HLS playlist (.m3u8), a DASH manifest (.mpd), or a YouTube live. In the Dashboard, this is a new live transcription at Transcriptions → New → Live whose source is a stream rather than the microphone. The address is set when the transcription is created and never changes, so a monitor is set up once and started whenever the station is worth recording.
The address has to be the stream itself, not the web page that plays it. A station's page is HTML; the audio it plays comes from somewhere else, usually an Icecast or Shoutcast server, and the page's player finds that address with JavaScript after it loads. Look on the site for a "Listen", "Direct stream" or "Other players" link: it ends in .mp3, .aac, .m3u, .m3u8 or .pls. A .pls or .m3u is not audio either. It is a short text file of a few lines, each giving the address of a stream; it exists so that desktop players can be handed a single link, and VocalStack transcribes the stream it names. If you paste the page instead, VocalStack requests it, sees HTML coming back and tells you so. Every station hides its stream a little differently; most hide it behind a button marked "Listen", which is the one thing on the page not worth clicking.
Two kinds of link are refused outright. Links to pages that play media, such as Spotify, SoundCloud or Twitch, are turned away before anything connects. Copy-protected streams are not supported either: a playlist or manifest that needs a DRM licence fails with a message that says so. Some streams also refuse requests from outside the station's country, so an address that plays in the office may not play from a server abroad. If a stream plays in a browser but not in VocalStack, the station is turning other players away; ask the station for an address that other apps are allowed to use. Most offer an MP3, AAC or HLS stream. Once you have the right address, the next question is whether it ever ends.
A live stream never ends, so it is not a file. The distinction matters for YouTube in particular. A YouTube live that is on air belongs in a live transcription, and the Dashboard follows it as it airs. A YouTube live that is scheduled but has not started is shown as Not live yet and can be recorded once it is on air. A finished video is a different thing: it has a length, so it is transcribed as a file: paste the link into Transcriptions → New.
The playlist itself says which it is, and that is how any player tells the difference. A finished HLS playlist carries an #EXT-X-ENDLIST tag or #EXT-X-PLAYLIST-TYPE:VOD; a live one has neither and keeps growing, so the player refetches it every few seconds for new segments. A DASH manifest declares type="dynamic" while the broadcast is on air and type="static" once it is a recording. An MP3 or AAC stream from an Icecast server has no length at all; it simply never stops.
From code, GET /v1/transcriptions/probe?url= settles this before anything is stored. The response's kind is live for a YouTube live that is on air or scheduled, an endless HTTP stream, an HLS playlist with no end, or a dynamic DASH manifest. It is file for anything with an end, and unknown when the probe could not tell. When the link did not open as media, ok is false and problem is a sentence you can show. The probe keeps nothing and is limited to 60 calls a minute.
File transcriptions run many times faster than the audio plays, so a finished hour of television does not take an hour. A live stream is transcribed in real time, but "real time" already runs behind the broadcast, and it is worth knowing by how much. An Icecast stream reaches a player a few seconds after the microphone. HLS and DASH are segmented, and a player will not start until it holds two or three segments of about six seconds each, so an HLS stream is typically 10 to 30 seconds behind the broadcast before transcription adds its own delay. A line that appears to arrive late is usually the station's delay, not the transcriber's. One stream makes one recording; a desk runs several, and they all end up in the same place.
Every live transcription lands in the Transcriptions library beside every file. Each recording is kept with its transcript, and once the words are final a title and summary are written for it, in every language. The spoken language is detected automatically, and speakers may switch language at any time. Where you know the language, naming it improves transcription quality.
The library is searchable across languages: search every transcript, whatever its language, and get the results in yours. A reporter who reads only English can search the Romanian station's morning show for a minister's name and read the hits in English, each with the transcription it came from and the time it was said. The minister's name will be spelt three ways across three stations; searching for it in English saves reading all three.
A transcription can be translated into up to 10 languages at once, so the same recording reads in every language the desk works in. A search hit is only useful if you can quote it.
A transcript is not a wall of text. The API's GET /v1/recordings/{id}/transcript returns sentences, segments with word timings, and speakers, so a quote can be placed to the second against the recording. The Dashboard replays a live recording exactly as it arrived, with its audio, so a sentence can be heard before it is quoted.
Before you trust any transcript of radio audio, from any system, two things are worth knowing. Speech recognition stumbles most on proper names, places and figures, which are exactly what a reporter searches for. A name the recogniser has never seen comes out as the nearest common word, and a search for the correct spelling misses it. Search for a distinctive word said in the same breath instead, then read around the hit. And radio is not all speech: music beds, jingles and advertising breaks produce lines that look like sentences but are not. Check the audio before you quote.
Speaker labels have three settings: off, on, or When Needed, which shows labels once a second speaker is heard. You can name a speaker in a recording (PUT /v1/recordings/{id}/speakers/{idx}), and once a speaker's voice is enrolled, future recordings recognise them by name. For a station whose presenters return every morning, the labels stop being "Speaker 2" after the first week. Once the quote is checked, it has to leave the building.
Each format on a transcription's Export tab has a job in a newsroom. SRT goes to the video editor, so a clip from the stream carries subtitles; a translated SRT carries them in another language. Excel goes to the researcher, one row per sentence with its time, to be filtered and annotated. PDF goes to the editor who wants to read the whole hour on the train. JSON goes to whoever is writing the desk's own tools. Through the API, the export is GET /v1/recordings/{id}/export?format=srt|json|xlsx|pdf, with lang= for a translated version. Download audio gives the recording as an MP3 for the package itself.
Monitoring a broadcast for reporting is normal newsroom practice. Republishing a clip of it is a different act. It is governed by fair dealing or fair use where you are, and by the station's own terms, so the desk's usual rules on quoting a competitor apply to the competitor's audio too. Everything above is a few clicks in the Dashboard; for a desk with twenty stations, it is better scripted.
The whole path is in the API, included in every plan and billed at the same rate as the Dashboard. A live transcription with a stream source is created idle, started by its first recording, and controlled over HTTP. Because the server pulls the audio, starting the recording returns no stream for you to publish to: there is nothing on your side that sends audio.
API=$VOCALSTACK_API_ORIGIN # the origin shown in the API reference
AUTH="Authorization: Bearer $VOCALSTACK_API_KEY"
# A live transcription whose source the server pulls itself.
TX=$(jq -n '{name: "Morning show", source: {kind: "stream", url: "https://example.org/live.mp3"},
settings: {speakerLabels: "auto"}}' \
| curl -sSf "$API/v1/transcriptions/live" -H "$AUTH" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" -d @- | jq -r .id)
# Start recording: the server opens the stream now.
REC=$(curl -sSf -X POST "$API/v1/transcriptions/$TX/recordings" -H "$AUTH" \
-H "Content-Type: application/json" -d '{}' | jq -r .recording.id)
# Later: pause, then stop (a live recording must be paused before it is stopped).
curl -sSf -X POST "$API/v1/recordings/$REC/pause" -H "$AUTH"
curl -sSf -X POST "$API/v1/recordings/$REC/stop" -H "$AUTH" -H "Content-Type: application/json" -d '{}'
# Search everything that was said, in English.
curl -sSfG "$API/v1/search" -H "$AUTH" --data-urlencode "q=budget" --data-urlencode "lang=en"
The Idempotency-Key makes a retried create return the first transcription instead of a second one. The TypeScript and Python SDKs wrap the same calls and are downloaded from the Developers area; the API reference has every route and its frames.
An AI agent can work the library without any code at all. The MCP server at /v1/mcp gives the agent a set of tools; among them, four matter here. search_transcriptions searches what was said across the account's transcriptions in any language and returns the matching lines, each with the transcription it is in and the time it was said. get_summary returns a recording's summary. transcribe_url and wait_for_transcription transcribe a finished video or a recording's link and wait for the result. Starting a live stream monitor stays with the Dashboard or the API above. The setup for Claude Code, Cursor or any Streamable HTTP client is under Developers → Connect an AI agent; the MCP article walks through it. What the script costs to run is the last question.
Live transcription is $0.50 per hour of audio, billed per minute ($0.0083 a minute). Live costs more than a file because it is transcribed as it happens, for as long as it runs. Files are $0.15 per hour ($0.0025 a minute; a 30-minute file costs $0.075). The rates are the same in every plan and through the API, and translations, summaries, speaker naming, broadcasting and sharing never add to the bill.
A station monitored eight hours a day, five days a week, is 40 live hours: $20 a week, whatever languages the desk reads it in.
The limits that matter for monitoring vary by plan. Each is listed in the order Pay as you go, Premium, Enterprise:
A new account starts with a $5 signup credit and no card, which is ten hours of live monitoring to try it on. The full table is on the pricing page.