# Speech to Text — Whisper Audio & Video Transcription (`nexgensignal/speech-to-text-transcription-api`) Actor

Transcribe audio and video files by link with the open Whisper model: MP3, M4A, WAV, MP4 and more, about 100 languages. Full text, timed segments, word timings, SRT/VTT subtitles, or translate to English. Billed per minute. Part of NexGen Signal — data tools and official-source data products

- **URL**: https://apify.com/nexgensignal/speech-to-text-transcription-api.md
- **Developed by:** [NexGen Signal](https://apify.com/nexgensignal) (community)
- **Categories:** AI, Videos, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $33.50 / 1,000 audio minutes

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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## 🎙️ Speech to Text — Whisper Audio & Video Transcription

Give direct links to **audio or video files** (MP3, M4A, WAV, OGG, FLAC, MP4, WebM, MOV and more) and get **a transcript of each file**: full text, timed segments, optional word timings, and ready-to-use SRT and WebVTT subtitles, in about 100 languages, or translated to English.

Transcription runs inside the actor with OpenAI's open Whisper model (base or small) through faster-whisper, so your audio is not sent to any outside speech service. Silence and music without speech are skipped, the language is detected automatically or set by you, and long recordings can be capped to their first minutes.

The unit of billing is one started minute of audio transcribed: a 20-second clip is 1 minute, a 40-minute episode is 40. Files with no speech, web pages, and files over your limits are not billed.

### Who buys this and for what job

- **Podcasters and video creators** making transcripts and subtitles for their episodes.
- **Researchers and journalists** turning recorded interviews and talks into searchable text.
- **AI builders** adding audio and video to a knowledge base.
- **Developers** needing a speech-to-text step in an Apify workflow without another account or API key.

Buyers usually search for this as **"speech to text"**, **"Whisper transcription"** or **"audio to text API"**.

### 📊 Sample Output

![Table of transcripts: file name, duration, language, minutes billed and the start of the text.](https://api.apify.com/v2/key-value-stores/IXCaMKjxSmUTLHhmq/records/speech-to-text-transcription-api.png)

| file_name | duration_seconds | language | minutes_billed | text |
|---|---|---|---|---|
| 590331main_ringtone_smallStep.mp3 | 12.98 | en | 1 | I'm going to step off the land now. It's one small step for man. One b … |
| 590325main_ringtone_kennedy_WeChoose.mp3 | 20.09 | en | 1 | We choose to go to the moon and disdicate and do the other things, not … |

Rows from live run `T3fwibcdgAwRSi1nB` on Apify (the Store example: two short NASA Apollo-era clips). Notice that short clips are billed as one started minute each.

### ✅ What you get

Every field of each record:

- `record_id`, `sha256`, `bytes` — file hash (record_id is its first 24 characters) and size.
- `url`, `final_url`, `file_name`, `content_type` — the link, where it was served from, the file name and type.
- `duration_seconds`, `transcribed_seconds`, `truncated`, `minutes_billed` — length of the recording, how much was transcribed (maxMinutesPerFile), and the started minutes billed.
- `language`, `language_probability`, `task`, `model` — the language (detected or set) with its confidence, transcribe or translate, and the Whisper model.
- `text`, `word_count` — the transcript.
- `segments` — timed segments (start and end in seconds, text), with word timings when wordTimestamps is on.
- `srt`, `vtt` — subtitles (with includeSubtitles).
- `processed_at` — when it was transcribed (UTC).

### ⚙️ Sample inputs

**Two short clips (the Store example)**

```json
{
  "mediaUrls": ["https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3", "https://www.nasa.gov/wp-content/uploads/2015/01/590331main_ringtone_smallStep.mp3"],
  "maxFiles": 10
}
```

About 2 minutes billed.

**Subtitles and word timings with the small model**

```json
{
  "mediaUrls": ["https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3"],
  "model": "small",
  "language": "en",
  "includeSubtitles": true,
  "wordTimestamps": true,
  "maxFiles": 1
}
```

SRT and VTT text in the row.

**First 40 minutes of a podcast episode**

```json
{
  "mediaUrls": ["https://example.com/episode.mp3"],
  "maxMinutesPerFile": 40,
  "maxFiles": 1
}
```

Caps the minutes billed per file.

Input fields:

| Field | Meaning |
|---|---|
| `mediaUrls` | direct audio or video file links (up to 500). Not YouTube or other video pages. |
| `model` | base (fast) or small (more accurate, slower); same price. |
| `language` | auto, or a code such as en, es, de, fr, ja. |
| `task` | transcribe, or translate to English. |
| `includeSegments`, `wordTimestamps`, `includeSubtitles` | timed segments (default on), word timings, SRT/VTT. |
| `vadFilter` | skip silence and music (default on). |
| `maxMinutesPerFile` | transcribe at most this many minutes per file (default 120, up to 300). |
| `maxFileMb` | skip files bigger than this (default 500). |
| `maxFiles` | stop after this many files (default 100). Billing is per started minute transcribed. |

### 🧾 JSON sample record

```json
{
  "record_id": "a51601dbbec037a31fc884bd",
  "url": "https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3",
  "final_url": "https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3",
  "file_name": "590325main_ringtone_kennedy_WeChoose.mp3",
  "content_type": "audio/mpeg",
  "bytes": 324921,
  "sha256": "a51601dbbec037a31fc884bdfc7fa7de24fc09251890c67b69e220c4c8cbe44f",
  "duration_seconds": 20.09,
  "transcribed_seconds": 20.09,
  "truncated": false,
  "minutes_billed": 1,
  "language": "en",
  "language_probability": 1,
  "task": "transcribe",
  "model": "small",
  "text": "We choose to go to the moon in this decade and do the other things, not because they are easy, but because they are hard. Three, two, one, zero. All engine running. Lift off. We have a lift off. 32 minutes past the hour. Lift off on Apollo 11.",
  "word_count": 49,
  "segments": [
    {
      "start": 0,
      "end": 7.7,
      "text": "We choose to go to the moon in this decade and do the other things, not because they are easy, but because they are hard.",
      "words": [
        {
          "word": "We",
          "start": 0,
          "end": 0.36,
          "probability": 0.801
        },
        {
          "word": "choose",
          "start": 0.36,
          "end": 0.76,
          "probability": 0.923
        },
        {
          "word": "to",
          "start": 0.76,
          "end": 1.08,
          "probability": 0.997
        },
        "… more words"
      ]
    },
    {
      "start": 7.82,
      "end": 19.78,
      "text": "Three, two, one, zero. All engine running. Lift off. We have a lift off. 32 minutes past the hour. Lift off on Apollo 11.",
      "words": [
        {
          "word": "Three,",
          "start": 7.82,
          "end": 8.14,
          "probability": 0.399
        },
        {
          "word": "two,",
          "start": 8.68,
          "end": 9.12,
          "probability": 0.982
        },
        {
          "word": "one,",
          "start": 9.8,
          "end": 10.22,
          "probability": 0.996
        },
        "… more words"
      ]
    }
  ],
  "srt": "1\n00:00:00,000 --> 00:00:07,700\nWe choose to go to the moon in this decade and do the other things, not because they are easy, but because they are hard.\n\n2\n00:00:07,820 --> 00:00:19,780\nThree, two, o …",
  "vtt": "WEBVTT\n\n00:00:00.000 --> 00:00:07.700\nWe choose to go to the moon in this decade and do the other things, not because they are easy, but because they are hard.\n\n00:00:07.820 --> 00:00:19.780\nThree, tw …",
  "processed_at": "2026-10-17T04:33:02Z"
}
```

### 🔧 How it works

Files are downloaded (3 at a time), decoded with FFmpeg (through PyAV) to 16 kHz mono, cut to maxMinutesPerFile, and transcribed one at a time with faster-whisper (int8 on CPU, beam search 5). The run uses 8 GB of memory by default, which gives it 2 CPU cores; more memory means more cores and faster runs.

Before a file is transcribed, its minutes are checked against your maximum charge: a file that would go over is skipped (not cut short) and smaller files can still follow.

Every run reads each host's robots.txt first: a path it disallows is skipped, listed in the run receipt and never charged. Only public internet addresses are fetched (no private, loopback or cloud-metadata addresses, checked again on every redirect). No logins, no CAPTCHA solving, no proxies.

Delivery is pushed first and charged after (the minutes for each file are charged when its row is delivered). The run receipt (`RUN_RECEIPT`) lists every link with its outcome and minutes, the robots.txt result per host, and the minutes delivered and charged.

### 💰 Pricing example

Per minute delivered, no start fee, no monthly charge:

| Apify plan | Price per minute |
|---|---|
| Free | $0.05 |
| Bronze | $0.045 |
| Silver | $0.04 |
| Gold, Platinum, Diamond | $0.0335 |

- The Store example, two short clips: 2 minutes = $0.10 on the Free plan, $0.067 on Gold.
- A 40-minute episode: $2.00 on Free, $1.34 on Gold.
- 10 hours of recordings: $30.00 on Free, $20.10 on Gold.

**Coverage and size.** Proof runs on 17 Oct 2026: the first 40 minutes of a 72-minute NASA podcast episode transcribed in about 4.5 minutes (7,128 words); the two Store-example clips in about 18 seconds. Accuracy depends on the recording; Whisper can mishear names and technical words, and the small model is more accurate than base.

### ⚖️ Legal & ToS

Recordings belong to their owners. You choose the links. Make sure you have the right to download and use the content you point it at; the actor fetches only what you give it (and, where you turn it on, what those pages link to).

The transcript is what the recording says; the actor adds nothing and does not identify speakers.

Every run reads each host's robots.txt first: a path it disallows is skipped, listed in the run receipt and never charged. Only public internet addresses are fetched (no private, loopback or cloud-metadata addresses, checked again on every redirect). No logins, no CAPTCHA solving, no proxies.

### ❓ FAQ

**Can I give a YouTube link?**
No. Give a direct link to the audio or video file.

**Is my audio sent to OpenAI or another service?**
No. The open Whisper model runs inside the actor.

**How is a minute counted?**
Started minutes of audio transcribed per file: 61 seconds is 2 minutes. Only the part up to maxMinutesPerFile is billed.

### 🆘 Troubleshooting

- **skipped: the link is a web page** — Give the direct file link (for podcasts, the enclosure URL from the feed).
- **Wrong language detected on a short clip** — Set language, e.g. en.
- **not processed: its N minute(s) would go over your maximum charge** — Raise your maximum charge or lower maxMinutesPerFile.
- **SOURCE UNAVAILABLE** — None of your links could be reached after retries. Nothing was charged.

### 🔗 Related Actors

- [PR Newswire Scraper](https://apify.com/nexgensignal/press-release-monitor-api) — press releases by company or topic
- [Website Tech Stack Detector](https://apify.com/nexgensignal/website-tech-stack-api) — what a site is built with
- [Brand Logo & Favicon Lookup](https://apify.com/nexgensignal/brand-logo-lookup-api) — a company's logo from its domain

🏢 **About NexGen Signal** — data tools and official-source data products on Apify. Browse the catalog: [apify.com/nexgensignal](https://apify.com/nexgensignal)

### ⭐ Found this useful?

If this actor saved you time, a rating on its Apify Store page helps other buyers find it.

Part of NexGen Signal — data tools and official-source data products.

# Actor input Schema

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

Direct file links (not YouTube or other video pages). Up to 500 per run.

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

Both cost the same per minute.

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

auto, or a language code such as en, es, de, fr, pt, ja, zh. Setting it avoids wrong detection on short clips.

## `task` (type: `string`):

Translate gives an English transcript of non-English speech.

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

Add segments with start and end times.

## `wordTimestamps` (type: `boolean`):

Add each word with its start, end and probability (slower).

## `includeSubtitles` (type: `boolean`):

Add ready-to-use subtitle text.

## `vadFilter` (type: `boolean`):

Skip long silences and music without speech (reduces made-up text).

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

Transcribe at most this many minutes from the start of each file.

## `maxFileMb` (type: `integer`):

Skip files bigger than this.

## `maxFiles` (type: `integer`):

Stop after this many files are transcribed. Billing is per started minute of audio transcribed; files with no speech are not billed.

## Actor input object example

```json
{
  "mediaUrls": [
    "https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3",
    "https://www.nasa.gov/wp-content/uploads/2015/01/590331main_ringtone_smallStep.mp3"
  ],
  "model": "base",
  "language": "auto",
  "task": "transcribe",
  "includeSegments": true,
  "wordTimestamps": false,
  "includeSubtitles": false,
  "vadFilter": true,
  "maxMinutesPerFile": 120,
  "maxFileMb": 500,
  "maxFiles": 10
}
```

# Actor output Schema

## `results` (type: `string`):

The delivered (and billed) records.

## `receipt` (type: `string`):

Per-link outcome, robots result, delivered and charged counts.

# 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://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3",
        "https://www.nasa.gov/wp-content/uploads/2015/01/590331main_ringtone_smallStep.mp3"
    ],
    "maxFiles": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("nexgensignal/speech-to-text-transcription-api").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://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3",
        "https://www.nasa.gov/wp-content/uploads/2015/01/590331main_ringtone_smallStep.mp3",
    ],
    "maxFiles": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("nexgensignal/speech-to-text-transcription-api").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://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3",
    "https://www.nasa.gov/wp-content/uploads/2015/01/590331main_ringtone_smallStep.mp3"
  ],
  "maxFiles": 10
}' |
apify call nexgensignal/speech-to-text-transcription-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nexgensignal/speech-to-text-transcription-api"
        }
    }
}
```

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/RovF68dc1LFofWr5a/builds/95d6rOdC6wGv88hZ5/openapi.json
