# Audio & Video Transcriber - Speech to Text, SRT & Timestamps (`readable_slash/audio-video-transcriber`) Actor

Transcribe audio and video to text with Whisper inside the Actor - no API key. Any direct media URL. Returns text, timestamped segments, SRT/VTT subtitles and optional RAG chunks. Built for long recordings: repetition loops and silence hallucinations are repaired. Billed per minute of speech.

- **URL**: https://apify.com/readable\_slash/audio-video-transcriber.md
- **Developed by:** [HJL Analytics and AI development](https://apify.com/readable_slash) (community)
- **Categories:** AI, Videos, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $24.00 / 1,000 audio minute transcribeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Audio & Video Transcriber — Speech to Text, SRT & Timestamps

Turn any audio or video file into accurate, timestamped text. Whisper runs
**inside the Actor** — no API key, no external service, nothing to sign up for.

Built for the recordings that break other transcribers: **long ones**.

***

### Why long recordings break most transcribers

Whisper is excellent on a clean three-minute clip. On a two-hour podcast,
lecture or meeting it has three well-documented failure modes, and most
transcription tools ship with none of them handled:

| What goes wrong | What you get back |
|---|---|
| **Repetition loops** | The same clause emitted hundreds of times. A 90-minute recording returns *"Thanks for watching. Thanks for watching. Thanks for watching…"* for forty minutes. |
| **Silence hallucination** | Dead air, music beds and room tone produce confident, fluent sentences that nobody said. |
| **Timestamps swallowing silence** | One six-word line stamped as lasting 50 seconds, because a pause got absorbed into it. Your subtitle sits on screen for a minute and your billing counts silence as speech. |

This Actor detects and repairs all three — and **tells you when it did**, in a
`repairs` field. A transcript that quietly threw away a minute of audio is
worse than one that says so.

***

### What you get

#### Accurate text, in the shape you need

- **Plain text** — the whole transcript.
- **Paragraphs** — split at natural pauses, so an hour-long transcript is
  actually readable instead of one wall of words.
- **SRT** and **WebVTT** subtitles — correctly formatted, with
  non-overlapping cues that players will not flicker on.
- **Timestamped segments** — every recognised span with start and end times.

#### Timestamped chunks for RAG (optional)

Turn on `chunkForRag` and the transcript comes back as retrieval-ready chunks:

```json
{
  "index": 7,
  "timestamp": "00:12:34 - 00:13:10",
  "start": 754.0,
  "end": 790.0,
  "text": "The second thing we changed was the onboarding flow..."
}
```

- A chunk **never splits a sentence**, so boundaries never land mid-thought.
- Chunks prefer to break at a **real pause**, graded by how long the silence
  was — a 20-second gap is a topic change, a 1-second one is a breath.
- **Every chunk carries its timestamp**, so a search hit can be cited or
  played back at the exact second it was said.

That last point is the difference between a transcript you can search and one
you can *use*. Most tools hand you text with no way back to the audio.

#### Automatic language detection

90+ languages, detected automatically, or pin it explicitly with `language`
for a faster and more reliable run.

#### Built for batches

One row per file. A 404, an unreadable file or a recording with no speech
returns a row with `status: "error"` (or a clear warning) and **never aborts
the run**.

***

### How to use it

1. Paste one or more **direct media URLs** into **Media URLs**. Anything you
   can link to works — a file on your own server, an S3 or Drive direct link,
   a podcast episode enclosure.
2. Pick a **model**. `base` is the default and handles clean speech well;
   choose `small` for heavy accents, background noise or overlapping speakers.
3. Choose your **output formats** — plain text, paragraphs, **SRT**, **VTT**,
   or several at once. Turn on **RAG chunks** if the transcript is going into
   a vector database.
4. **Start** the run. Results appear as one dataset row per file, with the
   transcript, timestamps and subtitles together.

Every run is a normal Apify run, so you can schedule it, trigger it from the
**API**, or wire it into **Make**, **Zapier**, **LangChain** or **LlamaIndex**.

### Pricing — you are charged for speech, not for silence

**Billed per minute of *detected speech*, rounded up per file.**

- A two-hour recording containing five minutes of talking bills **five
  minutes**, not 120.
- Silence, music-only and room-tone files bill **nothing**.
- Failed downloads and unreadable files bill **nothing**.
- A run that transcribes nothing costs **nothing**.

Most transcribers bill the full length of the file regardless. Paying for dead
air on a recording you did not edit is not a service you should have to buy.

***

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mediaUrls` | array | — | **Required.** Direct links to audio/video files or podcast enclosures. |
| `model` | string | `base` | `tiny`, `base` or `small`. Larger is more accurate on hard audio. |
| `language` | string | auto | ISO code (`en`, `nl`, `de`…). Empty = detect. |
| `outputFormats` | array | `["text"]` | Any of `text`, `paragraphs`, `srt`, `vtt`. |
| `includeSegments` | boolean | `true` | Timestamped spans. |
| `chunkForRag` | boolean | `false` | Also return timestamped retrieval chunks. |
| `chunkSize` | integer | `1200` | Soft character ceiling per chunk. |
| `chunkOverlap` | integer | `120` | Characters repeated between chunks. |
| `maxMinutesPerFile` | integer | `0` | Cost ceiling per file. `0` = no limit. |

#### Example

```json
{
  "mediaUrls": [
    "https://example.com/episode-42.mp3",
    "https://example.com/all-hands.m4a"
  ],
  "model": "base",
  "outputFormats": ["text", "srt"],
  "chunkForRag": true
}
```

### Output

```json
{
  "url": "https://example.com/episode-42.mp3",
  "filename": "episode-42.mp3",
  "status": "ok",
  "language": "en",
  "durationSeconds": 3612.4,
  "speechSeconds": 3380.1,
  "billedMinutes": 57,
  "model": "base",
  "text": "Welcome back to the show...",
  "srt": "1\n00:00:01,140 --> 00:00:04,140\nWelcome back to the show.\n...",
  "segments": [ { "index": 0, "start": 1.14, "end": 4.14, "text": "Welcome back to the show." } ],
  "chunks": [ { "index": 0, "timestamp": "00:00:01 - 00:01:12", "text": "..." } ],
  "repairs": ["trimmed silence inside 812.0-869.0s (57.0s of timeline for 31 characters of speech)"]
}
```

Failed files:

```json
{
  "url": "https://example.com/missing.mp3",
  "filename": "missing.mp3",
  "status": "error",
  "error": "http 404"
}
```

***

### Supported formats

`mp3`, `m4a`, `wav`, `flac`, `ogg`, `opus`, `aac`, `mp4`, `webm`, `mkv`, `mov`
and other common containers — the audio track is extracted automatically from
video files.

### Limitations — stated up front

- **No platform downloads.** This Actor does not fetch from YouTube, TikTok,
  Instagram, X or similar sites. It transcribes media you can link to
  directly. This is deliberate: platform scraping breaks constantly and
  violates those sites' terms.
- **No speaker diarization** in this version. Transcripts are not labelled
  "Speaker 1 / Speaker 2".
- **Accuracy depends on the audio.** Heavy accents, overlapping speech, poor
  microphones and background music all reduce quality — use the `small` model
  for difficult recordings.
- Text is transcribed in the language spoken; nothing is translated.

### Common uses

Podcast and interview transcripts; **webinar transcription** and **lecture
transcription**; meeting notes; subtitle generation (**SRT**/**VTT**); making
an audio or video archive **searchable**; accessibility captions.

For AI pipelines: **speech to text RAG** ingestion, where every chunk keeps the
**speech timestamps** it came from — so an answer can cite the moment something
was said, not just the file it was said in. Building a **RAG knowledge base**
from recordings, or feeding spoken content to an **LLM** with timestamps intact.

Any direct media URL works, so you can **transcribe MP3**, WAV, FLAC, M4A, MP4,
MOV and the other containers listed under Supported formats.

### Integrations

Standard Apify output: pull results via the **API**, export to
**JSON/CSV/Excel**, schedule runs, or connect to **Make**, **Zapier**,
**LangChain**, **LlamaIndex** and other Apify integrations.

### FAQ

**Is this legal?**
Yes. You supply media you already have the right to use, and the Actor
transcribes it. No third-party website is accessed, no terms of service are
involved, and no proxies are used. That is a deliberate design choice, not an
oversight — see the next answer.

**Can it transcribe a YouTube, TikTok or Instagram link?**
No, and it will not be added. Downloading from those platforms violates their
terms, needs paid proxies to work at all, and breaks whenever the platform
changes. If you need media from a social platform, fetch it with a tool built
for that and pass the resulting file URL here.

**How much will a run cost?**
You are charged **per minute of detected speech**, not per minute of file
length, so silence, music beds and dead air are free. A 45-minute interview
with 40 minutes of talking costs **$1.60**. A 3-minute voice note costs
**$0.12**. Failed files cost nothing at all.

**What happens if one file in my batch fails?**
Only that file. It appears in the dataset with `status: "error"` and the
reason, the rest of the batch continues, and **you are not charged for it**.

**Why is my transcript shorter than the recording?**
Check the `warning` field on that row. Either a per-file minute cap was set, or
the run's maximum cost would have been exceeded — the Actor stops rather than
transcribing audio it cannot bill for, and tells you which limit applied.

**Does it label who is speaking?**
No. Speaker diarization was built and tested against this Actor and reached
only 50–77% accuracy on real recordings, so it was not shipped. A transcript
where a quarter of the lines carry the wrong speaker is worse than one with no
labels — and charging for it would be worse still.

**Can I get the data out programmatically?**
Yes — the standard Apify dataset API, plus JSON, CSV and Excel export. Every
output field is described in the dataset schema, so tools and AI agents can
read the structure without guessing.

### Other Actors by this author

| Actor | What it does |
|---|---|
| [PDF Text Extractor — Markdown, Tables & RAG Chunks](https://apify.com/readable_slash/pdf-text-extractor-structured) | The same idea for documents: PDF to clean Markdown with real tables, heading structure and RAG-ready chunks. Pairs naturally with this Actor when a knowledge base mixes recordings and documents. |

# Actor input Schema

## `mediaUrls` (type: `array`):

Direct links to audio or video files, or podcast episode enclosures. Supports mp3, m4a, wav, flac, ogg, opus, aac, mp4, webm, mkv, mov and other common formats. This Actor does not download from YouTube, TikTok, Instagram or similar platforms - supply media you can link to directly.

## `model` (type: `string`):

Larger models are more accurate on difficult audio (accents, noise, crosstalk) and cost slightly more compute. 'base' is the balanced default and handles clear speech well.

## `language` (type: `string`):

ISO code such as en, nl, de, fr, es. Leave empty to detect automatically. Setting it explicitly is faster and more reliable when you already know the language.

## `outputFormats` (type: `array`):

Which renderings to include in each result row.

## `includeSegments` (type: `boolean`):

Return every recognised span with its start and end time.

## `chunkForRag` (type: `boolean`):

Group the transcript into retrieval-ready chunks that never split a sentence and carry the timestamp of what was said, so a search hit can be cited or played back at the exact second.

## `chunkSize` (type: `integer`):

Soft ceiling per chunk.

## `chunkOverlap` (type: `integer`):

Characters repeated between neighbouring chunks so a fact spanning a boundary stays retrievable.

## `maxMinutesPerFile` (type: `integer`):

Stop after this many minutes of each recording. 0 means no limit. Useful as a cost ceiling when processing files of unknown length.

## Actor input object example

```json
{
  "mediaUrls": [
    "https://archive.org/download/aesop_fables_volume_one_librivox/fables_01_08_aesop_64kb.mp3",
    "https://storage.googleapis.com/cloud-samples-tests/speech/brooklyn.flac"
  ],
  "model": "base",
  "outputFormats": [
    "text",
    "srt",
    "vtt"
  ],
  "includeSegments": true,
  "chunkForRag": true,
  "chunkSize": 1200,
  "chunkOverlap": 120,
  "maxMinutesPerFile": 0
}
```

# Actor output Schema

## `transcripts` (type: `string`):

One row per file: full text, timestamped segments, subtitles and any RAG chunks. Failed files appear with status "error" and a reason.

## `transcriptText` (type: `string`):

Just the language, duration and full transcript for each file.

## `subtitles` (type: `string`):

Ready-to-use SRT and WebVTT subtitle files for each recording.

## `ragChunks` (type: `string`):

Timestamped chunks ready for embedding, when RAG chunking is enabled.

## `runDetail` (type: `string`):

This run in Apify Console.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mediaUrls": [
        "https://archive.org/download/aesop_fables_volume_one_librivox/fables_01_08_aesop_64kb.mp3",
        "https://storage.googleapis.com/cloud-samples-tests/speech/brooklyn.flac"
    ],
    "outputFormats": [
        "text",
        "srt",
        "vtt"
    ],
    "chunkForRag": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("readable_slash/audio-video-transcriber").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mediaUrls": [
        "https://archive.org/download/aesop_fables_volume_one_librivox/fables_01_08_aesop_64kb.mp3",
        "https://storage.googleapis.com/cloud-samples-tests/speech/brooklyn.flac",
    ],
    "outputFormats": [
        "text",
        "srt",
        "vtt",
    ],
    "chunkForRag": True,
}

# Run the Actor and wait for it to finish
run = client.actor("readable_slash/audio-video-transcriber").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mediaUrls": [
    "https://archive.org/download/aesop_fables_volume_one_librivox/fables_01_08_aesop_64kb.mp3",
    "https://storage.googleapis.com/cloud-samples-tests/speech/brooklyn.flac"
  ],
  "outputFormats": [
    "text",
    "srt",
    "vtt"
  ],
  "chunkForRag": true
}' |
apify call readable_slash/audio-video-transcriber --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,readable_slash/audio-video-transcriber"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/EAAdVQNtZbbX6seqs/builds/mNM2AmTSXtbJkPEt7/openapi.json
