Audio & Video Transcriber — Speech to Text API avatar

Audio & Video Transcriber — Speech to Text API

Pricing

from $9.00 / 1,000 audio minutes

Go to Apify Store
Audio & Video Transcriber — Speech to Text API

Audio & Video Transcriber — Speech to Text API

Convert speech to text from any public audio or video URL: podcast episodes, MP3, WAV, M4A or MP4 files and video pages on other sites. Get timestamps, SRT/VTT subtitles, speaker labels and RAG-ready JSONL with source times. Up to 4 hours per file and 1,000 URLs per run. No speech API key needed.

Pricing

from $9.00 / 1,000 audio minutes

Rating

0.0

(0)

Developer

Sergey Andronik

Sergey Andronik

Maintained by Community

Actor stats

0

Bookmarked

20

Total users

8

Monthly active users

13 hours ago

Last modified

Share

Convert speech to text from any public audio or video URL. Audio & Video Transcriber is a speech-to-text API for podcast episodes, MP3, WAV, M4A and MP4 files, and video pages on other sites. It transcribes the audio itself with AI speech-to-text, so it works on recordings without captions. Each URL becomes one result with the full text, timestamps, SRT and VTT subtitles, optional speaker labels and optional RAG-ready passages that keep the source URL and original timestamps. Send one URL or up to 1,000 per run, with recordings of up to four hours. No speech-provider API key is needed.

This Actor accepts any public HTTPS audio or video URL. For the three big video platforms, the dedicated Actors below return the same transcript output and cost less:

Your linksBest ActorWhy
Podcast episodes, MP3/WAV/M4A/MP4 files, other sitesThis ActorDirect file links skip the download fee.
YouTube videosYouTube TranscriptBy default returns the video's caption track for $0.005 per video, and uses AI speech-to-text only when there is none.
TikTok videosTikTok Video Transcript$0.005 download and $0.008 per minute, against $0.02 and $0.01 here.
Instagram ReelsInstagram Reel Transcript$0.005 download and $0.005 per minute.

YouTube, TikTok and Instagram links still work here, at this Actor's prices.

What you get

  • Transcript text in text, plus transcript_llm with one line per segment for LLM prompts.
  • Timestamps per segment, or per word with timestamps: "word".
  • SRT and VTT subtitles in the result and as downloads in the run's key-value store, with an optional subtitle layout and QA report (subtitleProfile).
  • Readable paragraphs in paragraphs (start_s, end_s, speaker, text) and as transcript-000.txt and transcript-000.md downloads, at no extra charge. See Readable output.
  • Speaker labels with diarize: true.
  • RAG passages with exportRag: true: transcript passages with the source URL, original start and end seconds and versioned IDs, inline as rag_chunks and as a transcript-000.rag.jsonl download.
  • Intervals: transcribe only part of a recording with startTime and endTime; timestamps stay relative to the original recording.
  • Names and terminology: up to 100 glossary phrases to guide a compatible engine.
  • Billing per item: every row shows which events were charged.

How to transcribe audio or video to text

  1. Paste your URLs. Use public HTTPS links: a direct media file, a podcast episode page, a video page on another site, or a Google Drive or Dropbox share link to an audio or video file.
  2. Choose the output. Keep segment timestamps for subtitles. Turn on speaker labels or RAG passages if you need them.
  3. Set a run budget. In the run options, set a maximum charge for the run. maxTotalChargeUsd is a run option, not an input field. The run stops before work it cannot pay for.
  4. Start the run and open the Dataset. Each URL becomes one row. Download SRT, VTT and JSONL files from the run's key-value store.

Try it with a short recording

Open the RAG Task or paste this into the Input JSON editor:

{
"urls": ["https://storage.googleapis.com/cloud-samples-data/speech/commercial_mono.wav"],
"timestamps": "segment",
"exportRag": true
}

This is a 45-second public speech sample. Set the run's maximum charge to $0.10 for a first try. In the finished run, open the Dataset and look at text, segments and rag_chunks, then download transcript-000.srt and transcript-000.rag.jsonl from Storage; 000 is the URL's position in the input, starting at zero.

You can also inspect the RAG input, the sample passages and an earlier hosted transcript JSON, SRT and VTT without starting a run. The Task guide covers transcripts, speakers, intervals and subtitle presets.

Input

FieldWhat it does
urlsUp to 1,000 public HTTPS audio or video URLs, up to 8,192 characters each. Required unless you set datasetId.
datasetIdRead URLs from another run's dataset. See Chain from another Actor.
datasetUrlField, maxItemsThe dataset field that holds the URL (detected when empty), and how many rows to read (default 100, at most 1,000).
exportRagAdds rag_chunks and a .rag.jsonl download. Needs segment or word timestamps.
languageOptional language hint such as en, ru or pt-BR. Omit it for automatic detection.
timestampsnone (text only: no segments, words, SRT or VTT), segment (default) or word.
diarizeSpeaker labels, billed at the speaker-label rate. Labels from separately processed chunks of a long recording do not identify the same person; check speaker_scope.
subtitleProfilestandard (42 characters per line, 1–7 s cues) or short (28 characters per line, 0.5–4 s cues), with a subtitle QA report. Longer segments are split into cues within their time range. Needs segment or word timestamps. Leave it out for the plain layout without a report.
startTime, endTimeTranscribe only this interval, in seconds. The whole source is still downloaded.
glossaryUp to 100 names or terms, 1–80 characters each and 500 bytes in total. Glossary requests use Deepgram Nova-3.
providerPin one speech engine instead of automatic routing: groq/whisper-large-v3, groq/whisper-large-v3-turbo, openai/gpt-transcribe, openai/whisper-1, openai/gpt-4o-mini-transcribe, openai/gpt-4o-transcribe-diarize or deepgram/nova-3. A pin never switches engines; combinations it cannot serve fail with an error.

The advanced reference covers engine compatibility, subtitle QA and recovery in detail.

Start from a podcast feed

Put RSS or Atom feed URLs, or Apple Podcasts show pages, in Podcast feeds (feedUrls) to transcribe the newest episodes:

{
"feedUrls": ["https://feeds.simplecast.com/Sl5CSM3S", "https://podcasts.apple.com/us/podcast/the-daily/id1200361736"],
"maxItemsPerSource": 3,
"publishedAfter": "2026-10-01"
}
  • An Apple Podcasts show page is resolved to its public feed through Apple's lookup API. An episode link (?i=…) is rejected: pass that episode's audio URL in urls.
  • Episodes are taken newest first by publication date. Each episode's audio or video file is transcribed like a direct media URL, so there is no platform download fee. Each row adds source_url, source_type, source_title, episode_title, episode_guid and published_at.
  • publishedAfter (YYYY-MM-DD, UTC) leaves out older episodes; episodes without a date are left out too when it is set.
  • Feeds are downloaded with the same safety checks as media links (public addresses only, 32 MB at most). Feed URLs are shown without their query, and long token-like parts of their path (20 or more URL-safe characters before any file extension, unless they are lowercase words joined by hyphens or underscores) appear as ***, so a private subscriber token stays out of the results and error messages. Episode media URLs are shown as the feed lists them.
  • maxItemsPerSource (default 20, at most 200) limits how many of the newest items each source contributes. A run holds at most 1,000 items in total, counting urls and dataset rows.
  • Each listed item is processed and charged exactly like a URL you submit. Listing itself is free.
  • The example link in the URL list is processed and charged too: remove it when you want only listed items.
  • Listed items run after urls and dataset rows, source by source in input order; an item already in the run is skipped.
  • A source that cannot be listed becomes one error row with source_url and an error naming it (for example feedUrls[1]: …), and it is not charged. The other sources continue. If no source lists anything, the run fails before any charge.
  • The listing is saved when the run starts, so a restarted run keeps the same items even if the source changed meanwhile.

Scheduled runs: only new items

Turn on Skip items processed by earlier runs (skipPreviouslyProcessed) and run the Actor on a schedule to get only what is new since the last run.

  • The Actor keeps a key-value store named polyglot-processed-transcriber in your Apify account, or polyglot-processed-transcriber--<memoryKey> when you set Memory name (memoryKey), so separate schedules can keep separate memories. Other Actors keep their own stores, even with the same memoryKey. It records each item after the item is delivered and charged; failed items are tried again next time.
  • It applies to every URL in the run: listed ones, dataset rows and the items listed from sources.
  • When nothing is new, the run ends without any charge. Only error rows appear then, for sources or dataset rows that could not be used.
  • If the store cannot be opened or read, the run stops before any charge, and the next scheduled run tries again. If an item's record cannot be written, the item is still delivered and the log says so; a later run may process and charge it again.
  • Delete the store in Apify Console (Storage → Key-value stores) to start over. Do not run two runs with the same memory at the same time: both would process the same new items.

Chain from another Actor

Run a podcast, TikTok or Instagram scraper first, then paste the dataset ID of that run into Dataset ID (datasetId) to transcribe every one of its audio or video links:

{ "datasetId": "<dataset ID from the other run>", "maxItems": 200 }
  • The Actor reads up to maxItems rows (default 100) with your own run's Apify token and takes each row's URL from webVideoUrl, url, postUrl, videoUrl, inputUrl, link, audioUrl, mediaUrl, downloadUrl or an Instagram shortCode, or from the field you name in datasetUrlField.
  • Dataset URLs run after any urls you list, in dataset order; a dataset URL that is already in the run is skipped. A run takes at most 1,000 URLs in total.
  • A row without a usable URL becomes an error item with its dataset_row index, and it is not charged. Items from the dataset also carry dataset_row, so you can join the results back to the source rows.
  • The example link in the URL list is processed and charged too: remove it when you want only the dataset's items.

Output example

A real hosted result for the speech sample above, trimmed to 2 of 8 segments, with the text, SRT and VTT shortened:

{
"url": "https://storage.googleapis.com/cloud-samples-data/speech/commercial_mono.wav",
"text": "Okay, I'm here. Hi, I'd like to buy a Chromecast and I was wondering whether you could help me with that. …",
"language": "en",
"duration_s": 45.3,
"engine": "groq/whisper-large-v3",
"segments": [
{ "t0": 0, "t1": 3, "text": "Okay, I'm here." },
{ "t0": 3, "t1": 9, "text": "Hi, I'd like to buy a Chromecast and I was wondering whether you could help me with that." }
],
"srt": "1\n00:00:00,000 --> 00:00:03,000\nOkay, I'm here.\n\n…",
"usage": { "minutes": 1, "diarized": false, "platform_fetch": false },
"billing": {
"status": "paid",
"events": [{ "event": "audio-minute", "requested_count": 1, "charged_count": 1, "state": "confirmed" }]
}
}

With exportRag: true, each item also has rag_chunks. Each passage looks like this (identity hashes shortened):

{
"id": "p1",
"text": "Okay, I'm here. Hi, I'd like to buy a Chromecast …",
"start_s": 0,
"end_s": 42.66,
"source_url": "https://storage.googleapis.com/cloud-samples-data/speech/commercial_mono.wav",
"document_id": "doc_<sha256>",
"transcript_version": "transcript_<sha256>",
"chunker_version": "rag-v2",
"timing_basis": "segment"
}

A URL that fails returns a row with url and error. Very large results may carry result_record_key instead of inline text; read that key from the run's key-value store and use its value. artifact_errors lists any download that could not be saved.

Readable output

Every transcript row has paragraphs: the transcript in order, grouped into blocks you can read. A paragraph starts at a speaker change, after a pause of 2 seconds or more, and before it would pass 800 characters or 90 seconds. Once it holds 400 characters, the next sentence end closes it. No text is dropped or reordered, and a segment is never split in timed output. Each paragraph is { "start_s", "end_s", "speaker", "text" }; speaker appears only with diarize: true, and with timestamps: "none" there are no times and paragraphs are cut at sentence ends by length alone. Rows without speech have no paragraphs.

The same paragraphs are saved to the run's key-value store, numbered by input position:

  • transcript-000.txt: paragraphs separated by blank lines, with S1: style speaker labels.
  • transcript-000.md: a title (the video title when known), a list with the source URL, channel, language and duration, then each paragraph with its [mm:ss] (or [h:mm:ss]) start time and bold speaker label.
  • transcript-000.translated.txt and .md when translated segments exist.

When a row would pass the Dataset size limit, paragraphs is left out of the row first (the text stays) and the downloads still hold it. Both downloads are free, like SRT and VTT.

  • Embed or index each passage's text in your own system, and keep source_url, start_s and end_s with it so answers can cite the recording.
  • Use document_id:transcript_version:chunker_version:id as the index key. When you index a new version of a document, replace all its old passages.
  • Passages follow sentence boundaries, are at most 1,200 characters, and can merge nearby segments of the same speaker. timing_basis says whether a passage's times come from segments, matched words or an approximate segment range. Times are never invented from text length.
  • Check every item's error, stop_processing, billing and artifact_errors before indexing. A SUCCEEDED run alone does not mean every item is usable.

The Actor does the transcription and passage step. Embeddings, storage, retrieval and answer generation stay in your stack. The RAG tutorial walks through the handoff.

How much does speech to text cost?

Pay per event, with no subscription. These are the Free-plan prices; paid Apify plans get lower per-minute prices. The Pricing tab shows the current prices for your plan.

EventPriceWhen
Run setup$0.005Once per run.
Platform download$0.02Per page URL whose media was downloaded, for example a podcast page, a video page, an extensionless link or an HLS stream (.m3u8). Direct file links ending in .mp3, .wav, .m4a, .mp4 and other media file extensions skip it.
Audio minute$0.01Per started minute of the selected interval, after transcription succeeds.
Diarized audio minute$0.02Per started minute with speaker labels, instead of the audio minute.

Worked examples, without speaker labels:

Recording lengthDirect file, 1 URLDirect files, 100 URLsPage link, 1 URLPage links, 100 URLs
1 minute$0.015$1.005$0.035$3.005
3 minutes$0.035$3.005$0.055$5.005
10 minutes$0.105$10.005$0.125$12.005

For example, 100 direct files of 10 minutes cost $0.005 + 100 × 10 × $0.01 = $10.005. A 60-minute podcast MP3 costs $0.005 + 60 × $0.01 = $0.605, or $1.205 with speaker labels.

  • Minutes are rounded up once per file, and silence counts.
  • A recording with no detected speech (only music, silence or noise) returns no_speech: true with empty text and is not charged minutes, up to 30 such minutes per run; after that its minutes are charged. A page link still pays the platform download fee.
  • With startTime and endTime, only the selected minutes are charged; the platform download fee still applies to page links.
  • A successful platform download stays charged if the transcription fails afterwards. A download that is not a playable audio or video file, or is longer than four hours, is not charged.
  • RAG passages, subtitles and the QA report cost nothing extra.
  • Optional AI text add-ons, generated by Anthropic's Claude from the transcript: analysis (summary, chapters and action items together) $0.015 per URL, translation $0.015 per URL, keywords $0.008 per URL. Each is charged only after it succeeds. A transcript too long for an add-on's cost limit (about an hour for analysis, about 15 minutes for timed translation) returns an _error field instead and is not charged.
  • Apify's own small run-start event is separate and is shown on the Pricing tab.

maxTotalChargeUsd caps the whole run, not each recording. If a start request gets no answer, check your existing runs before you start another one.

Use it from the API, n8n or an AI agent

Start a run with the Apify API client for JavaScript and read the results:

import { ApifyClient } from 'apify-client'
const client = new ApifyClient({ token: process.env.APIFY_TOKEN })
const run = await client.actor('andronixmd/speech-to-text-transcriber').call(
{ urls: ['https://storage.googleapis.com/cloud-samples-data/speech/commercial_mono.wav'], timestamps: 'segment' },
{ maxTotalChargeUsd: 0.1 },
)
const { items } = await client.dataset(run.defaultDatasetId).listItems()
for (const item of items) console.log(item.url, item.error ?? item.text)
  • API: the API guide shows how to start once, poll the status, read every Dataset row and fetch saved files.
  • n8n: import the media-to-RAG workflow. It starts one transcription and emits one n8n item per passage. See the setup guide.

Use it from an AI agent (MCP)

Connect your agent to https://mcp.apify.com. It can find this Actor with search-actors, or call it by name, andronixmd/speech-to-text-transcriber, with call-actor. Use fetch-actor-details first for the input schema and pricing. Every call starts a new paid run, so always set callOptions.maxTotalChargeUsd and keep the urls list short:

{ "actor": "andronixmd/speech-to-text-transcriber", "input": { "urls": ["https://storage.googleapis.com/cloud-samples-data/speech/commercial_mono.wav"], "timestamps": "segment" }, "callOptions": { "maxTotalChargeUsd": 0.1 } }

call-actor returns the run status and storage IDs, not the results. Read the rows with get-dataset-items and the run's dataset ID. The fields to use are text, paragraphs and error.

With an Apify account, use your API token or MCP OAuth. Without one, an agent can buy a prepaid token from Apify AGI over x402 or MPP and use it as the Bearer token. It starts at $1, the balance is a hard spending cap, and the token expires after 14 days. This is experimental; see agentic payments.

Limitations

  • Public recordings only. Private, login-only, DRM-protected and region-blocked media is not supported. The Actor uses no accounts or cookies and does not try to get around access checks.
  • Podcast feeds, not channels. feedUrls lists RSS, Atom and Apple Podcasts shows. YouTube channels and playlists and TikTok profiles are listed by the YouTube and TikTok Actors in Related Actors; here, pass their video links.
  • Up to four hours per recording. That is a processing limit, not an accuracy promise for long recordings.
  • Not every page downloads. Sites change and some refuse automated downloads, so some URLs return an error row. Check each row's error and billing fields.
  • Speaker labels are per chunk on recordings that are processed in parts.

FAQ

Which audio and video formats work? Direct links to common media files, including MP3, WAV, M4A, AAC, OGG, OPUS, FLAC, MP4, MOV, MKV and WEBM, and public pages the downloader supports, such as podcast episode pages and X posts. HLS stream links (.m3u8) work too and are billed as page links.

Can I use Google Drive or Dropbox links? Yes, for a single file shared with "Anyone with the link". The Actor turns the share link into the provider's direct download link and bills it as a direct file, without the download fee. Folders are not supported. Google Drive shows a virus-scan page instead of the file for large files it cannot scan; those rows fail with a clear error, so use a direct link for them.

Which languages are supported? The language is detected automatically, and support depends on the engine. Pass a hint such as en, ru or pt-BR when you know it.

Can I transcribe a whole podcast feed? Yes. Put the feed URL or Apple Podcasts show page in feedUrls and set maxItemsPerSource. With skipPreviouslyProcessed on a schedule, each run transcribes only the new episodes.

Should I use this Actor for YouTube, TikTok or Instagram? It works, but the dedicated Actors in the table at the top are cheaper for those links.

Do you store my recordings? Results stay in your Apify run storage, under your account's access and retention settings. The audio is sent to the speech-to-text provider that transcribes it. Local working files are removed, but saved outputs and processing journals stay in the run storage. Only submit recordings you are allowed to process.