# Audio Speech-to-Text Transcriber (`automation-lab/audio-speech-to-text-transcriber`) Actor

Transcribe public audio and video URLs into text, timestamped segments, SRT, and VTT with local Whisper inference and no transcription API key.

- **URL**: https://apify.com/automation-lab/audio-speech-to-text-transcriber.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** AI, Videos, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 Speech-to-Text Transcriber

Convert speech in public audio and video files into transcript text, detected language, timestamped segments, and optional SRT/VTT subtitle files.

The Actor runs an open-source Whisper model inside the Apify container. It does not require an OpenAI, Deepgram, or other transcription API key.

Use it for podcast notes, interview research, accessibility captions, searchable media archives, or content-repurposing pipelines.

### What does Audio Speech-to-Text Transcriber do?

For every submitted direct media URL, the Actor:

1. Validates that the URL and redirects resolve to public network addresses.
2. Streams the file to bounded temporary storage.
3. Uses `ffprobe` to measure its duration.
4. Runs local Whisper speech recognition on CPU.
5. Produces complete text and timestamped segments.
6. Optionally saves SRT and VTT subtitle artifacts.
7. Removes temporary media before the run exits.

The default dataset receives one record per URL. A successful record contains the transcript. A failed URL produces an uncharged error record so batch users can see exactly what needs attention.

If every submitted URL fails, the run exits with a failure status.

### Who is it for?

- **Podcast and media teams** transcribing each new public recording.
- **Researchers and journalists** turning interviews or archives into searchable text.
- **Accessibility teams** generating a first-pass caption file for human review.
- **Content teams** feeding transcript text into summaries, articles, clips, or translations.
- **Developers and data engineers** adding repeatable speech recognition to scheduled Apify workflows.
- **Archivists** indexing public recordings that do not already have captions.

This Actor performs speech recognition. If a supported social video already has a published caption track and you only need to extract it, use [Video Transcript Scraper](https://apify.com/automation-lab/video-transcript-scraper) instead.

### Why use local speech recognition?

- No third-party transcription credential is needed.
- Media is not submitted to a separate paid transcription API.
- Input, output, limits, and errors have a stable machine-readable contract.
- Direct URLs can be processed in scheduled batches.
- Subtitle artifacts are available alongside normal dataset output.
- Charging begins only after the first useful transcription succeeds.

The bundled model is optimized for bounded CPU use rather than maximum accuracy. Review important transcripts before publication or compliance use.

### Supported input media

Provide direct, anonymously downloadable HTTP or HTTPS audio/video file URLs.

Common containers and codecs supported by FFmpeg/PyAV can work, including WAV, MP3, M4A, FLAC, MP4, WebM, and similar formats.

The URL must point to media bytes. A web page, podcast landing page, YouTube watch page, TikTok post, cloud drive preview, or authenticated download is not a direct media URL.

The Actor intentionally does not use a browser, proxy, account login, social downloader, or paid speech API.

### Input parameters

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `mediaUrls` | array | required | One to ten direct public media URLs. |
| `language` | string | `auto` | Automatic detection or a code such as `en`, `es`, `de`, or `pt-BR`. |
| `outputFormats` | array | `srt`, `vtt` | Optional subtitle artifacts. Use an empty array for dataset-only output. |
| `maxFileSizeMb` | integer | `250` | Per-file download limit, from 1 through 500 MB. |
| `maxDurationMinutes` | integer | `60` | Per-file duration limit, from 1 through 180 minutes. |

Language hints can improve speed or reliability when you already know the spoken language. Regional suffixes are accepted; inference uses the base language code.

### Getting started

1. Open the Actor in Apify Console.
2. Paste one or more direct media URLs into **Media URLs**.
3. Leave **Spoken language** at `auto`, or provide a known language code.
4. Choose whether to create SRT and VTT files.
5. Keep the default size and duration limits for your first run.
6. Click **Start**.
7. Open **Transcripts** for dataset records.
8. Open **Subtitle files** for generated artifacts.

A working small input is:

```json
{
  "mediaUrls": [
    { "url": "https://raw.githubusercontent.com/ggerganov/whisper.cpp/master/samples/jfk.wav" }
  ],
  "language": "en",
  "outputFormats": ["srt", "vtt"],
  "maxDurationMinutes": 5
}
```

### Output fields

| Field | Meaning |
| --- | --- |
| `sourceUrl` | Submitted direct media URL. |
| `status` | `succeeded` or `failed`. |
| `transcript` | Complete normalized transcript, or null on failure. |
| `language` | Detected/requested base language, or null on failure. |
| `languageProbability` | Whisper language-detection confidence. |
| `durationSeconds` | Duration measured by ffprobe when available. |
| `segments` | Ordered objects with `id`, `start`, `end`, and `text`. |
| `srtKey` | Key-value-store key for the optional SRT file. |
| `vttKey` | Key-value-store key for the optional VTT file. |
| `model` | Inference model used; currently `tiny`. |
| `processedAt` | ISO 8601 completion time. |
| `processingSeconds` | Wall-clock processing time for the item. |
| `error` | Bounded failure explanation, otherwise null. |

Representative output from the prefilled sample:

```json
{
  "sourceUrl": "https://raw.githubusercontent.com/ggerganov/whisper.cpp/master/samples/jfk.wav",
  "status": "succeeded",
  "transcript": "And so my fellow Americans ask not what your country can do for you ask what you can do for your country.",
  "language": "en",
  "languageProbability": 1,
  "durationSeconds": 11,
  "segments": [
    {
      "id": 0,
      "start": 0,
      "end": 11,
      "text": "And so my fellow Americans ask not what your country can do for you ask what you can do for your country."
    }
  ],
  "srtKey": "TRANSCRIPT_001.SRT",
  "vttKey": "TRANSCRIPT_001.VTT",
  "model": "tiny",
  "processedAt": "2026-01-15T12:00:00.000Z",
  "processingSeconds": 4.5,
  "error": null
}
```

### Subtitle artifacts

When requested, files use deterministic keys based on input order:

- `TRANSCRIPT_001.SRT`
- `TRANSCRIPT_001.VTT`
- `TRANSCRIPT_002.SRT`
- `TRANSCRIPT_002.VTT`

Artifact creation has no separate event charge. It is included in the successful audio-minute transcription event.

SRT uses comma millisecond separators. VTT uses dot millisecond separators and includes the `WEBVTT` header.

### How much does it cost to transcribe audio?

Pricing is pay per event. A **$0.005 start event** is charged only after the first successful transcription. Each successfully transcribed started audio minute then emits one `audio-minute` event. A run with no successful transcription has no event charge.

On the BRONZE tier, the current audio-minute price is **$0.01043 per started audio minute**. Other platform tiers receive the active tiered prices shown in Console.

Examples at the BRONZE rate, including the one-time start event:

- An 11-second recording rounds to one minute: **$0.01543**.
- A 10-minute recording: **$0.10930**.
- A 60-minute recording: **$0.63080**.

Rounding is applied separately to each successful URL. Apify platform usage may also be subject to your account plan and the active pricing displayed before a run.

### Batch and automation workflows

#### Podcast ingestion

Schedule a run whenever your feed pipeline discovers a new direct enclosure URL. Store transcript text in a search index and subtitle files with the episode assets.

#### Interview research

Submit a bounded batch, wait for the run, then export the dataset as JSON or CSV. Keep timestamps so researchers can return to the exact passage in the recording.

#### Accessibility review

Generate VTT, send it through a human correction step, and attach the reviewed file to the publishing system. Machine captions should be treated as a draft.

#### Content repurposing

Send the transcript to a summarizer, topic classifier, quotation finder, or translation Actor. Keep the source URL and timestamps for traceability.

### Run with the Apify API using cURL

Replace `YOUR_TOKEN` with an Apify API token:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~audio-speech-to-text-transcriber/runs?token=YOUR_TOKEN&waitForFinish=3600" \
  -H "Content-Type: application/json" \
  -d '{
    "mediaUrls": [{"url":"https://raw.githubusercontent.com/ggerganov/whisper.cpp/master/samples/jfk.wav"}],
    "language":"en",
    "outputFormats":["vtt"]
  }'
```

Fetch dataset items from the `defaultDatasetId` returned by the run.

### Run with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/audio-speech-to-text-transcriber').call({
  mediaUrls: [
    { url: 'https://raw.githubusercontent.com/ggerganov/whisper.cpp/master/samples/jfk.wav' },
  ],
  language: 'auto',
  outputFormats: ['srt', 'vtt'],
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].transcript);
```

### Run with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("automation-lab/audio-speech-to-text-transcriber").call(run_input={
    "mediaUrls": [
        {"url": "https://raw.githubusercontent.com/ggerganov/whisper.cpp/master/samples/jfk.wav"}
    ],
    "language": "en",
    "outputFormats": ["vtt"],
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items[0]["transcript"])
```

### Use with MCP and AI agents

Add the Apify MCP server to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/audio-speech-to-text-transcriber"
```

Use the same JSON under **Claude Desktop**, **Cursor**, or **VS Code** MCP settings:

```json
{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=automation-lab/audio-speech-to-text-transcriber"
    }
  }
}
```

Example prompts:

- “Transcribe this direct WAV URL and return the timestamped segments.”
- “Create VTT captions for these three public MP3 files.”
- “Run speech recognition in English and summarize the resulting dataset.”

### Limits and performance

- Maximum 10 URLs per run.
- Maximum configurable file size is 500 MB per URL.
- Maximum configurable duration is 180 minutes per URL.
- URLs and redirects resolving to loopback, link-local, private, or reserved networks are rejected.
- Authenticated URLs and URLs containing credentials are rejected.
- CPU transcription can take longer than the source duration for difficult or long media.
- The container uses the multilingual Whisper `tiny` model with CPU int8 inference.
- Very noisy speech, overlapping speakers, uncommon names, music, or low-bitrate audio can reduce accuracy.
- Speaker diarization, word-level timestamps, translation, and speaker labels are not currently provided.
- Social post pages and media that require a browser, cookies, login, or expiring client-side tokens are unsupported.

### Failure behavior and troubleshooting

**The URL produces HTTP 403 or 404.**

Confirm it is a direct anonymously downloadable file URL. Signed URLs may expire before a scheduled run starts.

**The Actor says the destination is private.**

Private hosts, localhost, internal object stores, and redirects into private address space are deliberately blocked. Provide a public HTTPS download URL instead.

**The record says no speech was detected.**

The media may contain silence, music, or speech too weak for the bundled model. Verify the file locally and try a clean speech recording.

**The language is wrong.**

Set `language` to a known code instead of `auto`.

**The run timed out.**

Use shorter files or split a long recording before submission. Keep the default 2 GB memory allocation because speech inference is memory intensive.

**Only some batch items failed.**

Filter the dataset by the status field. Successful items are still available and billed through the normal audio-minute event; failed records include their error and are uncharged.

### Privacy, legality, and responsible use

Only submit media you are authorized to download and process. Respect copyright, privacy, consent, employment, wiretapping, biometric, and data-protection requirements that apply to the recording and its speakers.

Do not use machine transcripts as the sole basis for legal, medical, safety, employment, or other high-impact decisions. Accuracy is not guaranteed. Review sensitive transcripts and captions with a qualified person.

The Actor prevents private-network URL access, but users remain responsible for the source URL and downstream handling of transcript data.

### Related Automation Lab Actors

- [Video Transcript Scraper](https://apify.com/automation-lab/video-transcript-scraper) — extract existing captions from supported social video sites.
- [YouTube Transcript](https://apify.com/automation-lab/youtube-transcript) — retrieve available YouTube transcript tracks without running speech inference.
- [Vimeo Transcript Scraper](https://apify.com/automation-lab/vimeo-transcript-scraper) — retrieve transcript/caption data from Vimeo workflows.

Choose this Actor when the input is a direct media file and speech recognition must generate the transcript.

### FAQ

#### Does it require an OpenAI or Deepgram key?

No. Inference runs with an open-source Whisper-compatible model inside the Actor container.

#### Does it download YouTube, TikTok, Instagram, or podcast pages?

No. V1 accepts direct public media file URLs only. Use a suitable downloader or caption extractor first when you have a web page rather than a media URL.

#### Are failed files charged?

No. The start and audio-minute events are emitted only after useful transcript text and segments have been produced. Failed URLs still receive an error record for diagnosis.

#### How are partial minutes billed?

Each successful file is rounded up independently. A 61-second file emits two audio-minute events.

#### Can it identify speakers?

No. Speaker diarization is not included.

#### Can I create only dataset output?

Yes. Set `outputFormats` to an empty array.

#### Is the transcript publication-ready?

Treat it as a machine-generated draft. Review names, punctuation, technical terms, and sensitive content before publishing.

# Actor input Schema

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

One to ten direct public HTTP(S) audio or video file URLs. Web pages and social post URLs are not supported.

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

Use auto to detect the language, or provide a code such as en, es, de, or pt-BR.

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

Optionally save SubRip (SRT) and/or WebVTT files in the run key-value store.

## `maxFileSizeMb` (type: `integer`):

Reject each download above this limit. The hard maximum is 500 MB.

## `maxDurationMinutes` (type: `integer`):

Reject media longer than this limit. The hard maximum is 180 minutes.

## Actor input object example

```json
{
  "mediaUrls": [
    {
      "url": "https://raw.githubusercontent.com/ggerganov/whisper.cpp/master/samples/jfk.wav"
    }
  ],
  "language": "auto",
  "outputFormats": [
    "srt",
    "vtt"
  ],
  "maxFileSizeMb": 250,
  "maxDurationMinutes": 60
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing successful transcripts and per-URL error records.

## `files` (type: `string`):

Key-value store containing optional SRT and VTT artifacts.

# 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": [
        {
            "url": "https://raw.githubusercontent.com/ggerganov/whisper.cpp/master/samples/jfk.wav"
        }
    ],
    "language": "auto",
    "outputFormats": [
        "srt",
        "vtt"
    ],
    "maxFileSizeMb": 250,
    "maxDurationMinutes": 60
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/audio-speech-to-text-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": [{ "url": "https://raw.githubusercontent.com/ggerganov/whisper.cpp/master/samples/jfk.wav" }],
    "language": "auto",
    "outputFormats": [
        "srt",
        "vtt",
    ],
    "maxFileSizeMb": 250,
    "maxDurationMinutes": 60,
}

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

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    {
      "url": "https://raw.githubusercontent.com/ggerganov/whisper.cpp/master/samples/jfk.wav"
    }
  ],
  "language": "auto",
  "outputFormats": [
    "srt",
    "vtt"
  ],
  "maxFileSizeMb": 250,
  "maxDurationMinutes": 60
}' |
apify call automation-lab/audio-speech-to-text-transcriber --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=automation-lab/audio-speech-to-text-transcriber",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/qumNzWI6uObak97aC/builds/hf1AdV25OmIWz7QEY/openapi.json
