# Audio Transcription - Speech to Text, Podcast RSS, SRT (`martin10291/audio-podcast-transcriber`) Actor

Audio transcription and speech to text with faster-whisper (tiny, base or small model, language auto-detect). Give mp3, m4a, wav, ogg or mp4 URLs or a public podcast RSS feed: one row per audio minute (text, start, end, language) plus the full TXT, SRT and VTT. Only-new mode for feeds.

- **URL**: https://apify.com/martin10291/audio-podcast-transcriber.md
- **Developed by:** [Martin Petrov](https://apify.com/martin10291) (community)
- **Categories:** AI, Videos, Integrations
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.60 / 1,000 results

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

## Audio & Podcast Transcription - Whisper on CPU, one row per minute, TXT/SRT/VTT, podcast RSS

Turn audio files and podcast episodes into text and subtitles. Give direct mp3, m4a, wav, ogg, flac, mp4 or webm URLs, or a public podcast RSS feed. **Measured:** 10.5 minutes of audio were transcribed in 91 seconds of total run time at 4096 MB (about 8x faster than real time, model `base`), so 1 hour of audio takes roughly 8 minutes. You pay per transcribed audio minute: one dataset row = one minute.

### What you get

- One dataset row per transcribed minute: `sourceUrl`, `episodeTitle`, `minute`, `start`, `end` (seconds), `text`, `language`, `feedUrl`, `published`.
- The full transcript as `.txt`, `.srt` and `.vtt` files in the run's key-value store. Public links are in every row (`transcriptTxtUrl`, `transcriptSrtUrl`, `transcriptVttUrl`, `transcriptJsonUrl`) and in the `RUN_SUMMARY` record.
- **Subtitle-ready SRT/VTT**: cues are timed from word timestamps, max 2 lines of 42 characters (set `subtitleMaxChars`, e.g. 32 for vertical Shorts/Reels/TikTok), max 7 seconds per cue, cut at sentence ends and pauses. Upload the `.srt` straight to YouTube, Premiere, DaVinci Resolve or CapCut.
- A `.json` file with every subtitle cue and **every word with its start/end time** (for karaoke captions, search inside audio, or clip cutting).
- Language auto-detection per file (or set `language`, for example `en`).
- Podcast RSS support: the newest `maxEpisodes` episodes of each feed (enclosure URLs are used). Apple Podcasts show links work too (the public RSS feed is looked up with Apple's official lookup API).
- Episode filters for feeds: `episodesSince` (a date or "30 days"), `titleIncludes` / `titleExcludes` (e.g. skip trailers and reruns).
- `vocabulary`: names and brands spoken in the audio, used as a spelling hint.
- Only-new mode: with `onlyNew` and a `monitorId`, episodes that were already transcribed are skipped and not charged again. Schedule the actor daily to transcribe every new episode of your feeds.
- `RUN_SUMMARY` record with counts (files, rows, audio minutes, compute seconds), per-file details and `lastError`.

### What it does not do

- No YouTube, TikTok or Instagram links (they need proxies and bot-detection workarounds; this actor does not use any). Only direct file URLs and public RSS feeds.
- No speaker labels (diarization). Quality depends on the model: `tiny` is fastest, `base` (default) is good for clear English, `small` is more accurate and handles other languages better but is slower.
- Whisper can mishear names and noisy audio; check important transcripts.
- Files up to 1.5 GB each. Silent minutes produce no row.

### Default input (about 1 minute)

The default input transcribes a 2.4 minute public-domain LibriVox recording (archive.org) and returns 3 rows.

### Input

| Field | Meaning |
|---|---|
| `urls` | Audio/video file URLs or podcast RSS feed URLs |
| `maxEpisodes` | Newest N episodes per feed (default 1) |
| `episodesSince` | Only episodes published on/after a date (`2026-10-01`) or within a period (`30 days`) |
| `titleIncludes`, `titleExcludes` | Keep / skip episodes by title text (`*` = anything) |
| `vocabulary` | Names and terms in the audio, e.g. `Apify, Kubernetes` (spelling hint) |
| `model` | `tiny`, `base` (default), `small` |
| `language` | Language code, empty = auto-detect |
| `maxMinutesPerFile` | Transcribe only the first N minutes (0 = all) |
| `onlyNew`, `monitorId` | Skip already transcribed episodes |

### API example

```bash
curl -X POST "https://api.apify.com/v2/acts/martin10291~audio-podcast-transcriber/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["https://feeds.example.com/my-podcast.xml"], "maxEpisodes": 1, "model": "base", "onlyNew": true, "monitorId": "my-podcast"}'
```

Example: the new episodes of a show from Apple Podcasts from the last 14 days, no trailers, with names spelled right (checked 2026-11-06: 6 matching episodes):

```json
{"urls": ["https://podcasts.apple.com/us/podcast/the-daily/id1200361736"], "maxEpisodes": 3, "episodesSince": "14 days",
 "titleExcludes": ["trailer"], "vocabulary": "Apify, Kubernetes", "onlyNew": true, "monitorId": "daily-interviews"}
```

### MCP (AI agents)

Add this actor as a tool: `https://mcp.apify.com?tools=martin10291/audio-podcast-transcriber`

### Pricing and measured cost

Price: $8.00 per 1,000 results = $0.008 per transcribed audio minute (one row per minute). Measured on Apify on 2026-11-04 (model `base`, int8, 4096 MB): 10.47 audio minutes took 91 s of run time and 0.101 compute units (about 0.0097 compute units per audio minute). A 2.4 minute file costs more per minute because of the fixed start-up (loading the model). At 2048 MB the same file took 123 s and 0.068 compute units, but 4096 MB is the default so long recordings do not run out of memory.

### Honest notes

Uses an honest User-Agent (`RadarTranscriber/1.0 (+apify.com/martin10291)`), no proxies. Only transcribe audio you have the right to use. Speech recognition: faster-whisper (CTranslate2) with OpenAI Whisper weights, running on CPU inside the actor, no external AI API.

### Use it as an integration (chain it after another actor)

This actor can run automatically after any actor whose results contain an audio file or podcast RSS feed.

1. Open the source actor in Apify Console and go to the **Integrations** tab.
2. Click **Add integration** -> **Actor**, pick this actor and set **Dataset** to `{{resource.defaultDatasetId}}` (leave `urls` empty). Set your other options and save.
3. When the source run finishes, this actor reads its dataset and processes every row. The field is detected automatically; set **Dataset field** if your column has another name.

You can also start it by hand with `datasetId` (pick a dataset or paste its ID) to process an existing dataset.

Good sources to chain from:

- martin10291/apple-podcasts-scraper (feedUrl)
- any actor with audioUrl / enclosureUrl / RSS feedUrl

# Actor input Schema

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

Direct links to audio or video files (mp3, m4a, wav, ogg, flac, mp4, webm, ...) or public podcast RSS feed URLs, or Apple Podcasts show links (podcasts.apple.com/.../id123; the public RSS feed is found automatically). For a feed the newest episodes are transcribed (see Max episodes per feed). YouTube, TikTok and Instagram links are not supported.

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

How many of the newest episodes to transcribe from each podcast RSS feed. Ignored for direct file URLs. Long episodes take long: about 1 hour of audio per few minutes of run time.

## `episodesSince` (type: `string`):

Podcast feeds only: keep episodes published on or after this date (YYYY-MM-DD) or within a period like '30 days', '2 weeks' or '3 months'. Applied before Max episodes per feed. Empty = no date filter.

## `titleIncludes` (type: `array`):

Podcast feeds only: transcribe only episodes whose title contains one of these texts (case-insensitive). \* matches anything, e.g. interview\*ceo. Empty = all titles.

## `titleExcludes` (type: `array`):

Podcast feeds only: skip episodes whose title contains one of these texts (case-insensitive), e.g. trailer, rerun, best of.

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

Speech recognition model (faster-whisper, runs on CPU inside the actor). tiny = fastest, base = good English quality at high speed (default), small = better accuracy and other languages, slower.

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

Two-letter language code of the audio, for example en, de, es, fr, bg. Leave empty to detect the language automatically for each file.

## `vocabulary` (type: `string`):

Names, brands or special terms spoken in the audio, comma separated, e.g. Apify, Kubernetes, Varna. Whisper uses them as a hint to spell them correctly. Max 400 characters. Empty = no hint.

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

Transcribe only the first N minutes of each file or episode (0 = the whole file). Use it to limit cost on very long recordings. You pay per transcribed minute.

## `subtitleMaxChars` (type: `integer`):

Max characters per subtitle line in the SRT and VTT files (2 lines per cue, max 7 seconds per cue, cut at sentence ends and pauses, timed from word timestamps). 42 is the broadcast standard; use 30-35 for vertical TikTok/Reels/Shorts videos.

## `onlyNew` (type: `boolean`):

For monitoring feeds: skip every file or episode that was already transcribed in an earlier run with the same Monitor ID and return only new ones. The first run transcribes everything it is asked for. Each minute is paid for once.

## `monitorId` (type: `string`):

Separate memory for each watch list (used with only-new mode). Use a different ID per podcast or feed list.

## `datasetId` (type: `string`):

Optional. Pick a dataset (or paste its ID) to read the input from, for example the result of Google Maps Scraper. When this actor runs as an integration, the dataset of the triggering run is used automatically (payload.resource.defaultDatasetId), so you can leave this empty. If set, the values found in the dataset replace the main input list.

## `datasetField` (type: `string`):

Optional. The item field that holds the value, for example website, url or videoUrl (dot paths like author.url work). Empty = detected automatically.

## `datasetMaxItems` (type: `integer`):

Upper limit of unique values taken from the dataset, to keep the cost under control.

## Actor input object example

```json
{
  "urls": [
    "https://archive.org/download/childrensshortworks09_1010_librivox/childrensshortworks009_lionandthehare_ab.mp3"
  ],
  "maxEpisodes": 1,
  "episodesSince": "",
  "titleIncludes": [],
  "titleExcludes": [],
  "model": "base",
  "language": "",
  "vocabulary": "",
  "maxMinutesPerFile": 0,
  "subtitleMaxChars": 42,
  "onlyNew": false,
  "monitorId": "default",
  "datasetMaxItems": 1000
}
```

# Actor output Schema

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

One row per transcribed minute of audio: sourceUrl, episodeTitle, minute, start, end, text, language, plus public links to the full transcript as TXT, SRT and VTT.

# 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://archive.org/download/childrensshortworks09_1010_librivox/childrensshortworks009_lionandthehare_ab.mp3"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("martin10291/audio-podcast-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://archive.org/download/childrensshortworks09_1010_librivox/childrensshortworks009_lionandthehare_ab.mp3"] }

# Run the Actor and wait for it to finish
run = client.actor("martin10291/audio-podcast-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://archive.org/download/childrensshortworks09_1010_librivox/childrensshortworks009_lionandthehare_ab.mp3"
  ]
}' |
apify call martin10291/audio-podcast-transcriber --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,martin10291/audio-podcast-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/SnMKZS2sVl1QZkMTW/builds/Ho7Lcwzfq4pPDKSBN/openapi.json
