# Podcast Transcription API — RSS feeds to episode transcripts (`amanatools/podcast-transcription-api`) Actor

Transcribe podcast episodes straight from an RSS feed. Pick the newest N per show, only episodes after a date, or only titles matching a phrase. Whisper runs inside the Actor — no API key. Show and episode metadata, text, SRT + VTT. Failed or silent episodes are never billed.

- **URL**: https://apify.com/amanatools/podcast-transcription-api.md
- **Developed by:** [Dos](https://apify.com/amanatools) (community)
- **Categories:** AI, Developer tools, Automation
- **Stats:** 3 total users, 2 monthly users, 0.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.

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

## Podcast Transcription API — RSS feeds to episode transcripts

Point it at a podcast RSS feed and get transcripts of **the episodes you
actually want** — the newest N of each show, everything published after a
date, or only episodes whose title matches a phrase. Whisper runs *inside*
the Actor (faster-whisper, int8, CPU), so there is **no API key, no external
service, and no per-provider markup.** 99 languages, auto-detected. Optional
translation to English.

Every item carries the show and episode metadata from the feed — show title,
author, episode number, season, publish date, GUID — next to the transcript,
so a podcast pipeline never has to resolve enclosure URLs or re-fetch the
feed to find out what it just transcribed.

Built for podcast search, show-notes generation, clip finding, media
monitoring and AI agents that need episodes as text.

### What you get

One dataset item per episode:

```json
{
  "feed_title": "Gravity Assist",
  "feed_author": "Brian Dunbar",
  "episode_title": "Season 5, Episode 32: Finale",
  "episode_number": 32,
  "season": 5,
  "published": "2022-08-12T18:21:00+00:00",
  "episode_guid": "…",
  "url": "https://www.nasa.gov/…/gafinale081222.mp3",
  "status": "ok",
  "language": "en",
  "duration_seconds": 1864.3,
  "billed_minutes": 32,
  "n_segments": 214,
  "n_words": 4930,
  "text": "Full transcript as one string …",
  "segments": [
    { "start": 0.0, "end": 6.48, "text": "Welcome back to the show." }
  ],
  "srt": "1\n00:00:00,000 --> 00:00:06,480\nWelcome back to the show.\n",
  "vtt": "WEBVTT\n\n00:00:00.000 --> 00:00:06.480\nWelcome back to the show.\n"
}
```

### Episode selection

| Field | Default | What it does |
|---|---|---|
| `feed_urls` | — | up to 10 RSS/Atom feeds, 40 MB each |
| `episodes_per_feed` | `3` | how many matching episodes to take per show |
| `published_after` | — | `2026-08-01`, or an ISO timestamp |
| `title_contains` | — | case-insensitive substring match on the title |
| `episode_urls` | — | extra direct audio URLs, transcribed alongside the feeds |

Filters combine: `published_after` **and** `title_contains` must both match.
Selection runs in feed order — which is newest-first for virtually every
show — and then takes the first `episodes_per_feed`.

Two deliberate behaviours worth knowing:

- **An episode whose feed gives no usable date survives a `published_after`
  filter.** Dropping it would hide episodes because the publisher's XML is
  sloppy, which is not your problem to debug.
- **A direct episode URL pasted into `feed_urls` is detected and transcribed
  as a single episode** instead of failing as a malformed feed.

Up to 50 episodes are queued per run, however the feeds divide it up.

### Pricing — pay only for delivered transcripts

| Event | Price | Charged when |
|---|---|---|
| `episode-transcribed` | $0.005 | an episode delivered a non-empty transcript |
| `transcription-minute` | $0.008 | per started minute of audio transcribed |

A 30-minute episode costs **$0.245**. A weekly show, 4 episodes a month, runs
about **$1**.

**There is no actor-start fee** — a start fee bills you for failed runs, and
this family never charges one.

The billing rule is deliberate: **episodes that fail to download, cannot be
decoded, or contain no recognizable speech are never billed — not even the
per-episode fee.** A feed that will not parse is reported in the dataset and
costs nothing. Your cost ceiling per episode = $0.005 + $0.008 × *Max minutes
per episode* (default 120).

### Transcription options

| Field | Default | Notes |
|---|---|---|
| `model` | `base` | `tiny` / `base` / `small` — accuracy vs speed |
| `language` | `auto` | ISO code (`en`, `ar`, `es`, …) skips detection |
| `task` | `transcribe` | `translate` = English text from any language |
| `vad_filter` | `true` | skip silence — faster, fewer hallucinated lines |
| `max_minutes_per_episode` | `120` | hard cost/length cap; longer episodes flagged `truncated` |

`tiny` and `base` are baked into the image and start instantly; `small`
downloads once at the start of the run (~1 minute extra).

### Re-running without paying twice

Each run checkpoints the episode URLs it finished, so a migrated or resumed
run never re-transcribes — and never re-charges — work it already delivered.
Across runs, deduplicate on `episode_guid`: it is the identifier the feed
itself considers stable.

### Limits, stated plainly

- CPU transcription: roughly 5–15 seconds of processing per audio minute
  with `base`, more with `small`. A 60-minute run timeout comfortably covers
  three 45-minute episodes with `base`; raise the timeout for longer batches
  or for `small`.
- 10 feeds per run, 25 episodes per feed, 50 episodes per run, 250 MB per
  episode, 480 minutes max per episode.
- Video podcasts work — the audio track is what gets transcribed.
- Feeds behind a paywall or private RSS token work only if the enclosure URL
  itself is fetchable without a login.

### The family

| Actor | Use it for |
|---|---|
| **Podcast Transcription API** (this one) | RSS feeds → episode transcripts + metadata |
| [Whisper Transcriber](https://apify.com/amanatools/whisper-transcriber) | any audio/video file → transcript text |
| [SRT Subtitles Generator](https://apify.com/amanatools/srt-subtitles-generator) | media → finished .srt / .vtt caption files |
| [PDF OCR Extractor](https://apify.com/amanatools/pdf-ocr-extractor) | scanned PDFs, Arabic + English OCR |

### Issues and requests

Open an issue on the actor's Issues tab — I read all of them.

# Actor input Schema

## `feed_urls` (type: `array`):

Podcast RSS/Atom feed URLs. Each feed expands to the episodes selected below. Up to 10 feeds per run (40 MB max per feed). A direct episode URL pasted here is detected and transcribed as a single episode.

## `episodes_per_feed` (type: `integer`):

How many matching episodes to take from each feed, in feed order (newest first for almost every show).

## `published_after` (type: `string`):

Only episodes published on or after this date, e.g. 2026-08-01. Episodes whose feed gives no usable date are kept rather than silently dropped. Leave empty for no date filter.

## `title_contains` (type: `string`):

Only episodes whose title contains this text (case-insensitive). Leave empty to take every episode.

## `episode_urls` (type: `array`):

Direct audio URLs to transcribe alongside the feeds — useful for a one-off episode that is not in any feed you are following.

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

Bigger models are more accurate and slower. 'base' is the sweet spot for clear speech; use 'small' for noisy audio, heavy accents or hard languages ('small' downloads on first use, adding ~1 minute once per run).

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

ISO code like 'en', 'ar', 'es', 'ru' — or 'auto' to detect. Setting it explicitly is slightly faster and more reliable.

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

'Transcribe' keeps the original language. 'Translate' produces English text regardless of the spoken language.

## `vad_filter` (type: `boolean`):

Voice-activity detection skips silent stretches — faster and fewer hallucinated lines on quiet audio. Turn off only if speech is being missed.

## `max_minutes_per_episode` (type: `integer`):

Hard cap on transcribed audio per episode — this is also your cost ceiling: max spend per episode = $0.005 + $0.008 x this number. Longer episodes are transcribed up to the cap and flagged 'truncated'.

## `include_failed_episodes` (type: `boolean`):

If enabled, episodes and feeds that fail still appear in the dataset with their status and error.

## Actor input object example

```json
{
  "feed_urls": [
    "https://www.nasa.gov/rss/dyn/Gravity-Assist.rss"
  ],
  "episodes_per_feed": 3,
  "model": "base",
  "language": "auto",
  "task": "transcribe",
  "vad_filter": true,
  "max_minutes_per_episode": 120,
  "include_failed_episodes": true
}
```

# Actor output Schema

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

Default dataset: one item per episode with feed\_title, episode\_title, published, text, segments, 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 = {
    "feed_urls": [
        "https://www.nasa.gov/rss/dyn/Gravity-Assist.rss"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("amanatools/podcast-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 = { "feed_urls": ["https://www.nasa.gov/rss/dyn/Gravity-Assist.rss"] }

# Run the Actor and wait for it to finish
run = client.actor("amanatools/podcast-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 '{
  "feed_urls": [
    "https://www.nasa.gov/rss/dyn/Gravity-Assist.rss"
  ]
}' |
apify call amanatools/podcast-transcription-api --silent --output-dataset

```

## MCP server setup

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