Audio & Video Transcriber: Speech to Text with Timestamps
Pricing
Pay per event
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
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
| Field | Required | What it does |
|---|---|---|
mediaUrls | yes | Direct https links to audio or video files |
language | no | A code such as en, es or de. Leave it empty to detect the language |
maxFiles | no | The 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
| Event | Price |
|---|---|
| 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-403is 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 Pathfrom transcript_core import FasterWhisperBackend, transcriberow = 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"))
- Every failure is a row with a reason.
REASONSmaps each reason to one status. A caller bug (akindthat is noturlorpath) raises instead. - 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 literalTrueproceeds. - No charge call in the core. The row carries
status,durationSecondsandaudioSeconds, which is what a charge needs. - One backend seam (
backend.py).FasterWhisperBackendis 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.