Audio & Video Transcriber: Speech to Text with Timestamps avatar

Audio & Video Transcriber: Speech to Text with Timestamps

Pricing

Pay per event

Go to Apify Store
Audio & Video Transcriber: Speech to Text with Timestamps

Audio & Video Transcriber: Speech to Text with Timestamps

Transcribe audio and video files to text with timestamps. Paste direct MP3, MP4, M4A, WAV or WEBM links and get the full transcript, timed segments, spoken language and duration as clean JSON. Whisper runs inside the Actor: no API key, no signup, nothing to install.

Pricing

Pay per event

Rating

0.0

(0)

Developer

FrameProbe

FrameProbe

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Transcribe audio and video files to text. Give it direct links to MP3, MP4, M4A, WAV, WEBM or MOV files and get one row per file: the full transcript, timed segments, the spoken language and the duration, as clean JSON. Whisper runs inside the Actor, so there is no API key to bring, no account to create and nothing to install.

  • Podcast and interview transcripts
  • Subtitles from the timed segments
  • Searchable text from a folder of recorded calls or lectures
  • A transcription step inside a pipeline: one URL in, one row out, the same keys every time

Input

FieldRequiredWhat it does
mediaUrlsyesDirect https links to audio or video files
languagenoA code such as en, es or de. Leave it empty to detect the language
maxFilesnoThe most files one run transcribes. Default 10, up to 100

mediaUrls also answers to urls, url, mediaUrl, videoUrls, audioUrls and startUrls, and takes a single string as well as a list.

{ "mediaUrls": ["https://example.com/interview.mp3"] }

Output

One row per file, with the same keys on every row, including the files that failed.

{
"source": "https://example.com/interview.mp3",
"status": "transcribed",
"reason": null,
"durationSeconds": 184.32,
"language": "en",
"text": "Welcome back to the show. Today we are talking about pricing.",
"segments": [
{ "startSeconds": 0.0, "endSeconds": 2.4, "text": "Welcome back to the show." },
{ "startSeconds": 2.4, "endSeconds": 5.1, "text": "Today we are talking about pricing." }
],
"wordCount": 12,
"model": "base"
}

A file that could not be transcribed has status set to failed, no_audio or no_speech, a reason from a fixed list your pipeline can branch on, and an error sentence saying what happened.

Cost

EventPrice
Actor start$0.01 per run
Minute of audio transcribed$0.009 per minute, rounded up, minimum one per file

A 40-second voice note costs $0.019 in a run of its own. Ten 3-minute interviews in one run cost $0.28. A single 10-minute file costs $0.10. A one-minute file took about 15 seconds end to end on the platform.

Not charged: files that fail to download, have no audio track, or are refused. They still get a row with the reason. A file with no spoken words is charged, because the model listened to all of it.

Set a maximum charge and the run stays inside it. Each file's length is read before any audio is decoded. A file that does not fit what is left gets a skipped row saying so, is not charged, and the run stops there.

What it does not do

  • Page links are not files. A YouTube, TikTok or Instagram page link comes back as a failed row. Run a scraper that returns the media file URL, and pass that.
  • Up to 200 MB and 10 minutes per file. A longer file is refused with a reason, not cut short.
  • Some hosts refuse cloud servers. A link that plays in your browser but fails here with download-403 is usually the host blocking datacenter addresses.
  • No speaker labels and no translation. One transcript, in the language spoken.
  • Accuracy is Whisper base's, and it has not been measured on this Actor yet.

Security

Only public https:// links are fetched. A link to a private or internal address is refused before anything is downloaded, on the first request and again on every redirect. One gap remains: a host name can give a public address when we check it and a private one when we connect (DNS rebinding). Nothing a file contains can make the Actor fetch anything else: ffmpeg reads local files only.

For developers: the package inside

The Actor wraps transcript_core, a package that knows nothing about Apify and charges nothing (tests/test_isolation.py fails if it ever does).

from pathlib import Path
from transcript_core import FasterWhisperBackend, transcribe
row = transcribe("https://cdn.example/clip.mp4", kind="url",
backend=FasterWhisperBackend("base"),
allow=lambda seconds: True if seconds <= 120 else "over this run's limit",
temp_root=Path("/tmp"))
  1. Every failure is a row with a reason. REASONS maps each reason to one status. A caller bug (a kind that is not url or path) raises instead.
  2. The duration is read before any work. allow(seconds) runs after the header probe and before the audio is decoded or the model is called. Only a literal True proceeds.
  3. No charge call in the core. The row carries status, durationSeconds and audioSeconds, which is what a charge needs.
  4. One backend seam (backend.py). FasterWhisperBackend is the only one implemented: CPU, int8, model from local disk only. The Dockerfile bakes the model into the image.

kind is never guessed from the string, and the Actor always passes kind="url", so a buyer's text that looks like a path is sent through the SSRF guard as a URL. The hardened download is a copy of reel-teardown's and is held to it by ../tests/test_core_drift.py.

Not known yet: whether faster-whisper runs fast enough on one core to price (A2 in PLAN-transcript-actors-2026-09-12.md), transcript quality, and the decode and model timeouts in CoreCaps, which are labelled guesses.

python -m pytest -q -p no:cacheprovider transcript-core/tests

Hermetic: an autouse fixture refuses every connection and hostname lookup. Needs ffmpeg and ffprobe on PATH.