Klistra in strömmen, inte sidan. En stations riktiga ljud finns på en adress som slutar på .mp3, .aac eller .m3u8, och när en livetranskribering väl har den behöver ingen lyssna längre.
En redaktion som bevakar tre radiostationer, två TV-strömmar och en handfull YouTube-livesändningar har först ett bemanningsproblem och sedan ett transkriberingsproblem. Någon måste lyssna, och någon måste trycka på inspelning. En livetranskribering med en ström som källa tar över båda jobben: ge den strömmens adress, så öppnar servern den, avkodar den och transkriberar den medan den sänds, så att ingen behöver sitta vid skrivbordet när en presskonferens börjar tidigt. Det svåra, visar det sig, är att hitta adressen.
En livetranskribering kan hämta ljudet från en ström som servern hämtar själv: en internetradiostation, en HLS-spellista (.m3u8), ett DASH-manifest (.mpd) eller en YouTube-livesändning. I dashboarden är detta en ny livetranskribering under Transcriptions → New → Live vars källa är en ström i stället för mikrofonen. Adressen sätts när transkriberingen skapas och ändras aldrig, så en bevakning sätts upp en gång och startas varje gång stationen är värd att spela in.
Adressen måste vara själva strömmen, inte webbsidan som spelar upp den. En stations sida är HTML; ljudet den spelar kommer från någon annanstans, oftast från en Icecast- eller Shoutcast-server, och sidans spelare hittar den adressen med JavaScript efter att sidan laddats. Leta på sajten efter en länk som heter "Listen", "Direct stream" eller "Other players": den slutar på .mp3, .aac, .m3u, .m3u8 eller .pls. En .pls eller .m3u är inte heller ljud. Det är en kort textfil på några rader, där varje rad anger adressen till en ström; den finns för att skrivbordsspelare ska kunna få en enda länk, och VocalStack transkriberar strömmen den pekar på. Klistrar du in sidan i stället begär VocalStack den, ser HTML komma tillbaka och säger till om det. Varje station gömmer sin ström lite olika; de flesta gömmer den bakom en knapp märkt "Listen", och det är det enda på sidan som inte är värt att klicka på.
Två slags länkar avvisas direkt. Länkar till sidor som spelar media, som Spotify, SoundCloud eller Twitch, stoppas innan någon anslutning görs. Kopieringsskyddade strömmar stöds inte heller: en spellista eller ett manifest som kräver en DRM-licens misslyckas med ett meddelande som säger just det. Vissa strömmar vägrar dessutom anrop från utanför stationens land, så en adress som spelas upp på kontoret kanske inte spelas upp från en server utomlands. Om en ström spelas i en webbläsare men inte i VocalStack, stänger stationen ute andra spelare; be stationen om en adress som andra appar får använda. De flesta erbjuder en MP3-, AAC- eller HLS-ström. När du har rätt adress är nästa fråga om den någonsin tar slut.
En livestream tar aldrig slut, så den är inte en fil. Skillnaden spelar roll särskilt för YouTube. En YouTube-livesändning som är på väg ska ligga i en livetranskribering, och dashboarden följer den medan den sänds. En YouTube-livesändning som är schemalagd men inte har börjat visas som Not live yet och kan spelas in när den väl sänds. En färdig video är något annat: den har en längd, så den transkriberas som en fil. Klistra in länken under Transcriptions → New.
Spellistan själv säger vilket det är, och så kan alla spelare skilja dem åt. En färdig HLS-spellista har taggen #EXT-X-ENDLIST eller #EXT-X-PLAYLIST-TYPE:VOD; en levande har ingen av dem och växer hela tiden, så spelaren hämtar den på nytt var få sekund för nya segment. Ett DASH-manifest deklarerar type="dynamic" medan sändningen pågår och type="static" när den är en inspelning. En MP3- eller AAC-ström från en Icecast-server har ingen längd alls; den bara slutar aldrig.
Från kod avgör GET /v1/transcriptions/probe?url= detta innan något lagras. Svarets kind är live för en YouTube-livesändning som är på väg eller schemalagd, en ändlös HTTP-ström, en HLS-spellista utan slut eller ett dynamiskt DASH-manifest. Det är file för allt med ett slut, och unknown när probet inte kunde avgöra det. När länken inte öppnades som media är ok false och problem en mening du kan visa. Probet sparar ingenting och är begränsat till 60 anrop per minut.
Filtranskribering går många gånger snabbare än ljudet spelas upp, så en färdig timme TV tar inte en timme. En livestream transkriberas i realtid, men realtid ligger redan efter sändningen, och det är värt att veta med hur mycket. En Icecast-ström når en spelare några sekunder efter mikrofonen. HLS och DASH är segmenterade, och en spelare startar inte förrän den har två eller tre segment om cirka sex sekunder vardera, så en HLS-ström ligger typiskt 10 till 30 sekunder efter sändningen innan transkriberingen lägger till sin egen fördröjning. En rad som verkar komma sent beror oftast på stationens fördröjning, inte på transkriberaren. En ström ger en inspelning; en redaktion kör flera, och de hamnar alla på samma ställe.
Varje livetranskribering hamnar i biblioteket Transcriptions, bredvid varje fil. Varje inspelning sparas med sitt transkript, och när orden väl är slutgiltiga skrivs en titel och en sammanfattning för den, på alla språk. Talat språk identifieras automatiskt, och talare får byta språk när som helst. När du vet språket hjälper det transkriptionskvaliteten att ange det.
Biblioteket går att söka i över språken: sök i alla transkript, oavsett språk, och få träffarna på ditt eget språk. En reporter som bara läser engelska kan söka i den rumänska stationens morgonprogram efter en ministers namn och läsa träffarna på engelska, var och en med transkriberingen den kommer från och tidpunkten då det sades. Ministerns namn stavas på tre olika sätt i tre stationer; att söka på det på engelska sparar att läsa alla tre.
En transkribering kan översättas till upp till 10 språk samtidigt, så samma inspelning kan läsas på alla språk redaktionen arbetar med. En sökträff är bara användbar om du kan citera den.
Ett transkript är inte en textvägg. API:ets GET /v1/recordings/{id}/transcript returnerar sentences, segments med ordtider och speakers, så ett citat kan placeras till sekunden mot inspelningen. Dashboarden spelar upp en livesändning precis så som den kom in, med ljudet, så att en mening kan höras innan den citeras.
Innan du litar på något transkript av radioljud, från vilket system som helst, finns två saker att känna till. Taligenkänning snubblar mest på egennamn, platser och siffror, precis det en reporter söker efter. Ett namn igenkännaren aldrig har sett blir det närmaste vanliga ordet, och en sökning på rätt stavning missar det. Sök i stället efter ett utmärkande ord som sägs i samma andetag och läs runt träffen. Och radio är inte bara tal: musikbäddar, jinglar och reklampauser ger rader som ser ut som meningar men inte är det. Kontrollera ljudet innan du citerar.
Talaretiketter har tre lägen: av, på eller When Needed, som visar etiketter när en andra talare hörs. Du kan namnge en talare i en inspelning (PUT /v1/recordings/{id}/speakers/{idx}), och när en talares röst är inlärd känner framtida inspelningar igen den vid namn. För en station vars programledare återkommer varje morgon slutar etiketterna vara "Talare 2" efter första veckan. När citatet är kontrollerat måste det lämna huset.
Varje format på fliken Exportera i en transkribering har en uppgift på redaktionen. SRT går till videoredigeraren, så ett klipp från strömmen får undertexter; en översatt SRT får dem på ett annat språk. Excel går till researchern, en rad per mening med tidpunkt, för att filtreras och annoteras. PDF går till redigeraren som vill läsa hela timmen i tåget. JSON går till den som skriver redaktionens egna verktyg. Via API:et är exporten GET /v1/recordings/{id}/export?format=srt|json|xlsx|pdf, med lang= för en översatt version. Download audio ger inspelningen som en MP3 för själva paketet.
Att bevaka en sändning för rapportering är vanlig redaktionell praxis. Att återpublicera ett klipp av den är något annat. Det styrs av citaträtt eller motsvarande regler där du befinner dig, och av stationens egna villkor, så redaktionens vanliga regler för att citera en konkurrent gäller även konkurrentens ljud. Allt ovan är några klick i dashboarden; för en redaktion med tjugo stationer är det bättre att skripta det.
Hela vägen finns i API:et, ingår i varje abonnemang och faktureras till samma pris som i dashboarden. En livetranskribering med en strömkälla skapas i viloläge, startas av sin första inspelning och styrs över HTTP. Eftersom servern hämtar ljudet returnerar inspelningens start ingen ström för dig att publicera till: det finns inget på din sida som skickar ljud.
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"
Idempotency-Key gör att ett återförsökt skapande returnerar den första transkriberingen i stället för en andra. TypeScript- och Python-SDK:erna omsluter samma anrop och laddas ned från utvecklarområdet; API-referensen har varje route och deras format.
En AI-agent kan arbeta med biblioteket utan någon kod alls. MCP-servern på /v1/mcp ger agenten en uppsättning verktyg; bland dem är fyra viktiga här. search_transcriptions söker i det som sagts i kontots alla transkriberingar på vilket språk som helst och returnerar de matchande raderna, var och en med transkriberingen den finns i och tidpunkten den sades. get_summary returnerar en inspelnings sammanfattning. transcribe_url och wait_for_transcription transkriberar en färdig video eller en inspelnings länk och väntar på resultatet. Att starta en bevakning av en livestream sker fortfarande i dashboarden eller i API:et ovan. Inställningen för Claude Code, Cursor eller valfri Streamable HTTP-klient finns under Developers → Connect an AI agent; MCP-artikeln går igenom den. Vad skriptet kostar att köra är den sista frågan.
Livetranskribering kostar $0.60 per timme ljud, faktureras per sekund ($0.01 per minut), med en minimiavgift på 5 minuter per transkribering. Live kostar mer än en fil eftersom den transkriberas medan det händer, så länge den pågår. Filer kostar $0.20 per timme ($0.0033 per minut; en fil på 30 minuter kostar $0.10). Priserna är desamma i varje abonnemang och via API:et, och översättningar, sammanfattningar, namngivning av talare, sändning och delning ökar aldrig fakturan.
En station som bevakas åtta timmar om dagen, fem dagar i veckan, är 40 livetimmar: $24 i veckan, oavsett på vilka språk redaktionen läser den.
Gränserna som spelar roll för bevakning varierar med abonnemanget. Varje gräns anges i ordningen Pay as you go, Premium, Enterprise:
Ett nytt konto börjar med en registreringskredit på $5 utan kort, vilket är mer än åtta timmars livebevakning att prova på. Hela tabellen finns på prissidan.