# Whisper Transcriber: Audio, Video & Podcast Speech to Text (`cprussin/media-transcriber`) Actor

Transcribe audio and video files or podcast RSS feeds with Whisper: full text, timestamped segments, SRT and VTT subtitles, language detection and RAG chunks. Direct file URLs or uploads (not YouTube links). New-episodes mode. No API key. From $0.008 per audio minute.

- **URL**: https://apify.com/cprussin/media-transcriber.md
- **Developed by:** [Connor Prussin](https://apify.com/cprussin) (community)
- **Categories:** AI, Videos, Developer tools
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 audio minute (base model)s

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Whisper Transcriber: Audio, Video & Podcast to Text, SRT and VTT

**Whisper Transcriber** turns **audio files, video files and podcast RSS feeds** into **text**, **timestamped segments**, **SRT and VTT subtitles** and **RAG-ready chunks**, with **automatic language detection**. It runs OpenAI's open-source **Whisper** model (via faster-whisper) inside the actor: **no API key, no OpenAI account, no per-token fees**. Paste file links, point it at your own uploads, or give it a podcast feed and schedule it to transcribe **only new episodes**.

- ✅ **Any audio or video file**: MP3, M4A, WAV, OGG, OPUS, FLAC, AAC, MP4, MOV, MKV, WEBM and more. Video files are fine: only the audio track is used.
- ✅ **Podcast RSS feeds** with a **new-episodes mode**: schedule the actor daily and each new episode is transcribed exactly once.
- ✅ **SRT and VTT subtitles** for every file, plus the full text and **timestamped segments** in the dataset.
- ✅ **Language detection** across Whisper's 99 languages, or set the language yourself.
- ✅ **RAG chunks with start and end times**, ready for a vector database. Pairs with [Document to Markdown](https://apify.com/cprussin/document-to-markdown?fpr=to54nm) for PDFs and Office files.
- ✅ **No API key**: Whisper runs inside the actor. Your audio isn't sent to an AI provider.
- ✅ **Batch-safe**: a 404, a web page, a corrupt or over-long file never fails the run. You get an item with the reason, for free.
- ✅ **Pay per audio minute**: $0.008/min (base model) or $0.016/min (small model). No start fee.

### Start in one minute

Click **Start** with the prefilled input:

```json
{
  "urls": [
    "https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3"
  ]
}
```

You get: A transcript of a 20-second NASA clip of JFK's "We choose to go to the Moon" speech: `text`, timestamped `segments`, detected `language`, `durationSeconds`, and `srtUrl`/`vttUrl` subtitle links.

**Cost:** $0.008: 1 minute × $0.008 (base model, billed per started minute). No start fee.

### Use with an AI assistant

Connect the [Apify MCP server](https://mcp.apify.com) to Claude, ChatGPT, Cursor or any MCP client (`https://mcp.apify.com?tools=cprussin/media-transcriber` loads only this actor), then paste:

```text
Use the Apify actor cprussin/media-transcriber to transcribe https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3, and give me the text and the SRT subtitle link.
```

### Recipes

#### New podcast episodes, daily

The 3 newest episodes of a feed; schedule the same input daily to transcribe only new ones.

```json
{
  "rssFeeds": ["https://feeds.example.com/my-podcast.xml"],
  "maxEpisodes": 3,
  "onlyNewEpisodes": true,
  "model": "base"
}
```

#### Interviews with the more accurate model

Your own uploaded recording, English, with the `small` model.

```json
{
  "keyValueStoreRecords": ["my-user~interviews/call-2026-10-01.m4a"],
  "model": "small",
  "language": "en"
}
```

#### RAG chunks with timestamps

One item per chunk, each with its start and end time.

```json
{
  "urls": [
    "https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3"
  ],
  "outputFormat": "chunks",
  "chunkSize": 1000,
  "chunkOverlap": 100
}
```

#### Skip long files

Files over 30 minutes are skipped with a free error item.

```json
{
  "urls": [
    "https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3"
  ],
  "maxDurationMinutes": 30
}
```

### What can I use audio and video transcription for?

- **Podcast monitoring and research**: transcribe every new episode of the shows you follow, then search, summarize or quote them.
- **Subtitles and captions**: SRT/VTT files for videos, courses, webinars and social clips.
- **RAG and AI assistants**: chunk transcripts with timestamps, embed them, and link answers to the exact minute.
- **Content repurposing**: turn talks, interviews and videos into blog posts, show notes, newsletters or LLM prompts.
- **Meetings and interviews**: transcribe recordings you upload to an Apify key-value store.
- **AI agents**: give an agent a "listen to this file" tool through the Apify API or MCP server.

### How does it work?

1. Each file is downloaded (with size and time limits), each key-value store record is read, and each RSS feed is fetched for its newest episodes.
2. [FFmpeg](https://ffmpeg.org/) decodes the audio track to 16 kHz mono. Files longer than **Max duration** are skipped (free).
3. [faster-whisper](https://github.com/SYSTRAN/faster-whisper) transcribes it on CPU with voice activity detection, which skips silence and music and reduces hallucinated text.
4. You get the text, segments, detected language and duration, and links to the SRT and VTT files.

### How do I transcribe audio, video or a podcast?

| Field                  | Description                                                               | Default          |
| ---------------------- | ------------------------------------------------------------------------- | ---------------- |
| `urls`                 | Direct links to audio or video files, one per line                        | a 20 s NASA clip |
| `startUrls`            | Same, in Apify request-list format (combined with `urls`)                 | none             |
| `keyValueStoreRecords` | Uploaded files, as `storeId/recordKey` or `username~store-name/recordKey` | none             |
| `rssFeeds`             | Podcast RSS or Atom feed URLs                                             | none             |
| `maxEpisodes`          | Newest episodes per feed to consider                                      | `5`              |
| `onlyNewEpisodes`      | Skip episodes transcribed by an earlier run with the same feeds           | `false`          |
| `model`                | `base` (fast, $0.008/min) or `small` (more accurate, $0.016/min)          | `base`           |
| `language`             | `auto` or a language code (`en`, `de`, `es`, `fr`, `ja`, `zh`, ...)       | `auto`           |
| `outputFormat`         | `transcript` (one item per file) or `chunks` (one item per RAG chunk)     | `transcript`     |
| `chunkSize`            | Max characters per chunk, overlap included                                | `1500`           |
| `chunkOverlap`         | Characters of whole segments repeated from the previous chunk             | `150`            |
| `maxDurationMinutes`   | Longer files are skipped with a free error (at most 300)                  | `180`            |
| `maxFileSizeMb`        | Larger downloads are skipped with a free error                            | `1000`           |
| `timeoutSecs`          | Max download time per file                                                | `600`            |

**Transcribing your own recordings:** upload them to a key-value store in your Apify account (Storage → Key-value stores → your store → upload a record) and list them in `keyValueStoreRecords`, e.g. `my-user~interviews/call-2026-10-01.m4a`. Private record URLs (`https://api.apify.com/v2/key-value-stores/.../records/...`) also work in `urls`; the actor reads them with your run's token.

**YouTube, TikTok and Instagram links are not supported** (you get a free error item). For YouTube captions, use [YouTube Transcripts](https://apify.com/cprussin/youtube-transcripts?fpr=to54nm).

### What data do you get?

**Transcript** (`outputFormat: "transcript"`): one item per file (shortened):

```json
{
  "url": "https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3",
  "sourceType": "url",
  "title": "590325main_ringtone_kennedy_WeChoose.mp3",
  "model": "base",
  "language": "en",
  "languageProbability": 0.9672,
  "durationSeconds": 20.088,
  "billedMinutes": 1,
  "text": "We choose to go to the moon and disdicate and do the other things, not because they are easy, but because they are hot. Three, two, one, zero, all engine running. Lift off, we have a lift off, 32 minutes past the hour, lift off on Apollo 11.",
  "segments": [
    {
      "start": 0.0,
      "end": 7.8,
      "text": "We choose to go to the moon and disdicate and do the other things, not because they are easy, but because they are hot."
    }
  ],
  "segmentCount": 3,
  "wordCount": 48,
  "srtUrl": "https://api.apify.com/v2/key-value-stores/.../records/transcript-0001.srt",
  "vttUrl": "https://api.apify.com/v2/key-value-stores/.../records/transcript-0001.vtt",
  "warning": null,
  "error": null,
  "transcribedAt": "2026-10-07T13:20:00.000Z"
}
```

That is the fast `base` model; `small` gets this clip word-perfect ("...in this decade... because they are hard."). Podcast episodes also have `feedUrl`, `podcastTitle`, `episodeGuid` and `publishedAt`, and `title` is the episode title.

**RAG chunks** (`outputFormat: "chunks"`): one item per chunk, with the same file fields plus `chunkIndex`, `chunkCount`, `startTime` and `endTime` (seconds), and the chunk's `text`. Chunks break between Whisper segments, so every chunk maps to an exact time range.

- **SRT and VTT** files are saved in the run's key-value store as `transcript-0001.srt` / `.vtt` and linked from every item.
- Failed files are returned with `text: null` and an `error`, such as `Download failed: HTTP 404.`, `This link is a web page, not an audio or video file.`, `The media is 212.4 min long, over the 180.0 min limit (maxDurationMinutes).` or `No speech detected.`

### How much does audio transcription cost?

Pay per event, per **started minute** of audio actually transcribed. No subscription, no start fee, compute included:

| Model                   | Price per audio minute | 1-hour podcast |
| ----------------------- | ---------------------- | -------------- |
| `base` (default)        | **$0.008**             | $0.48          |
| `small` (more accurate) | **$0.016**             | $0.96          |

A 30 min 20 s file is billed as 31 minutes. Failed files, files over your limits and episodes skipped by new-episodes mode are free. If you set a **maximum cost per run**, the actor never starts a file the remaining budget can't pay for: it skips it with a free error item and moves on to shorter files.

### Tips

- **Which model?** `base` is fine for clear speech (podcasts, lectures, audiobooks). Use `small` for accents, noisy recordings, crosstalk, names and most non-English audio.
- **Speed**: on the default 4 GB memory (1 CPU core), `base` transcribes about 9 minutes of audio per minute and `small` about 3. More memory gives more cores (4 GB per core) and faster runs.
- **Language**: auto-detection uses the start of each file. Set the language for short clips or when the first seconds are music or another language.
- **Long files**: the default run timeout may be too short for many hours of audio with `small`; raise the run timeout or split the batch.
- **Podcasts**: use the show's RSS feed URL (on Apple Podcasts, Spotify-for-Creators, Buzzsprout, Libsyn, Podbean and other hosting pages, or search the show name plus "RSS"). `maxEpisodes` caps each run; with `onlyNewEpisodes`, only the newest `maxEpisodes` episodes are checked for new ones.

### FAQ

**Is this OpenAI's Whisper API?** No. It runs the open-source Whisper `base` and `small` models (MIT license) locally inside the actor with faster-whisper and CTranslate2. No API key, no data sent to OpenAI.

**Which languages are supported?** All 99 Whisper languages, with automatic detection. Accuracy is best for English and widely spoken languages; use the `small` model for others.

**Does it identify speakers?** No, there is no speaker diarization. Segments have timestamps but no speaker labels.

**Can I transcribe YouTube or TikTok videos?** Not by page link. Use direct media file links, your own uploads or podcast feeds. For YouTube captions, see [YouTube Transcripts](https://apify.com/cprussin/youtube-transcripts?fpr=to54nm).

**How long can a file be?** Up to `maxDurationMinutes` (default 180, at most 300). Longer files are skipped for free.

**Can AI agents use it?** Yes, through the Apify API, the Apify MCP server or any Apify integration (Make, Zapier, n8n, LangChain, LlamaIndex).

**Disclaimer:** You are responsible for having the right to process the media you submit.

### Open-source software

This actor is built on [faster-whisper](https://github.com/SYSTRAN/faster-whisper) and [CTranslate2](https://github.com/OpenNMT/CTranslate2) (MIT), OpenAI's [Whisper](https://github.com/openai/whisper) model weights (MIT) and [FFmpeg](https://ffmpeg.org/) (an LGPL-2.1 build, decoders only). See `THIRD_PARTY_NOTICES.md` in the source for all notices. It is not affiliated with or endorsed by OpenAI, SYSTRAN or the FFmpeg project.

### Related actors

- [YouTube Transcript Scraper](https://apify.com/cprussin/youtube-transcripts?fpr=to54nm): YouTube transcripts as text, segments, SRT or VTT, for AI and RAG.
- [Video Frame Extractor](https://apify.com/cprussin/video-frame-extractor?fpr=to54nm): Thumbnails, scene keyframes, contact sheets and GIFs from video files.
- [PDF to Markdown Converter](https://apify.com/cprussin/document-to-markdown?fpr=to54nm): PDF, Word, PowerPoint, Excel and EPUB to Markdown or RAG chunks.

# Actor input Schema

## `urls` (type: `array`):

Direct links to audio or video files (MP3, M4A, WAV, OGG, OPUS, FLAC, MP4, MOV, MKV, WEBM and anything else FFmpeg reads), one per line. Apify key-value store record URLs are read with your token. YouTube, TikTok and Instagram page links are not supported. Billed per started minute of audio; failed files are free.

## `startUrls` (type: `array`):

Optional alternative to Audio and video URLs, in Apify's request-list format (e.g. a file with one URL per line, or the output of another actor). Combined with Audio and video URLs.

## `keyValueStoreRecords` (type: `array`):

Files uploaded to an Apify key-value store, as <code>storeId/recordKey</code> or <code>username~store-name/recordKey</code>, one per line. Use this to transcribe your own recordings without hosting them anywhere.

## `rssFeeds` (type: `array`):

Podcast RSS (or Atom) feed URLs, one per line. The newest episodes of each feed are transcribed (see Max episodes per feed).

## `maxEpisodes` (type: `integer`):

How many of each feed's newest episodes to consider. With Only new episodes, those already transcribed by an earlier run are skipped.

## `onlyNewEpisodes` (type: `boolean`):

Skip episodes transcribed by an earlier run with the same feeds. Schedule the actor (e.g. daily) to transcribe each new episode once. Failed episodes are retried next run. State is kept in the key-value store "media-transcriber-state" in your account.

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

Base: fast and cheap, good for clear speech ($0.008/min). Small: more accurate on accents, noise, names and non-English audio ($0.016/min, about 3x slower).

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

Spoken language. Auto-detect works well for one language per file; set it for short clips, strong accents or to force a language.

## `outputFormat` (type: `string`):

Transcript: one item per file with the full text and timestamped segments. RAG chunks: one item per chunk of about the chosen size, with start and end times, ready for a vector database. SRT and VTT subtitle files are saved and linked in both.

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

RAG chunks only. Maximum characters per chunk, overlap included. Chunks break between transcript segments. About 4 characters make one token.

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

RAG chunks only. Up to this many characters of whole segments repeated from the end of the previous chunk, at most half the chunk size. 0 for none.

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

Longer files are skipped with an error (free). Caps cost per file. At most 300.

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

Larger downloads are skipped with an error (free). Video files are large: the audio track is all that is used.

## `timeoutSecs` (type: `integer`):

Max time to download one file.

## Actor input object example

```json
{
  "urls": [
    "https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3"
  ],
  "maxEpisodes": 5,
  "onlyNewEpisodes": false,
  "model": "base",
  "language": "auto",
  "outputFormat": "transcript",
  "chunkSize": 1500,
  "chunkOverlap": 150,
  "maxDurationMinutes": 180,
  "maxFileSizeMb": 1000,
  "timeoutSecs": 600
}
```

# Actor output Schema

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

No description

## `chunks` (type: `string`):

No description

# 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 = {
    "urls": [
        "https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("cprussin/media-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 = { "urls": ["https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3"] }

# Run the Actor and wait for it to finish
run = client.actor("cprussin/media-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 '{
  "urls": [
    "https://www.nasa.gov/wp-content/uploads/2015/01/590325main_ringtone_kennedy_WeChoose.mp3"
  ]
}' |
apify call cprussin/media-transcriber --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cprussin/media-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/JrkwRZ98AP8DFfl8c/builds/bQRl7drSVjT5gRj6V/openapi.json
