# Podcast Transcript API - RSS, Apple Podcasts & Audio to Text (`catalyst-labs/podcast-transcript-api`) Actor

Get podcast and audio transcripts as text, timestamped segments, SRT/VTT and Markdown. Input: RSS feeds, Apple Podcasts links, episode pages or audio/video URLs. Uses the publisher's own transcript when one exists ($0.01), Whisper speech-to-text otherwise.

- **URL**: https://apify.com/catalyst-labs/podcast-transcript-api.md
- **Developed by:** [Catalyst Labs](https://apify.com/catalyst-labs) (community)
- **Categories:** AI, Videos, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 episode transcript (publisher)s

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

## Podcast Transcript API: RSS, Apple Podcasts & audio to text

Get a transcript for any podcast episode or audio/video file as **plain text, timestamped segments, SRT, VTT, LLM-ready text and Markdown**, with episode metadata. When the show publishes its own transcript (the Podcasting 2.0 `podcast:transcript` tag), you get that for a flat **$0.01 per episode**. Otherwise the audio is transcribed with **Whisper large-v3 (turbo as automatic fallback)** and billed per audio minute.

### For AI agents

- **What it does:** podcast RSS feed / Apple Podcasts link / episode page / audio URL in, one transcript record per episode out.
- **Minimal input:** `{"sources": ["https://podnews.net/rss"], "maxEpisodesPerFeed": 1}`
- **Cheap first call:** the input above returns the newest Podnews episode from its publisher transcript: **$0.01**.
- **MCP tool:** `catalyst-labs--podcast-transcript-api` (via `https://mcp.apify.com/?tools=catalyst-labs/podcast-transcript-api`).
- **Cost controls:** `maxEpisodesPerFeed` (default 3), `maxAudioMinutes` (default 120 speech-to-text minutes per run), `maxMinutesPerEpisode` (default 180), `transcriptMode: "publisherOnly"` (never transcribes), plus the run option `maxTotalChargeUsd`. The run checks the budget **before** transcribing each episode, so it never overshoots.
- **Key output fields:** `transcriptSource` (`publisher` | `speechToText`), `text`, `llmText`, `segments[{start,end,text,speaker}]`, `srt`, `vtt`, `markdown`, `speakers`, `chapters`, `language`, `durationSeconds`, `chargedEvent`, `chargedMinutes`; failures carry `errorType`, `retryable`, `hint`.
- **Known limits:** Spotify-exclusive and Apple-subscription shows have no public audio (rejected, not charged; pass the RSS feed). YouTube links: use `catalyst-labs/youtube-transcript-api`. Speech-to-text has no speaker labels (publisher transcripts keep theirs).

### When to choose this tool

- Choose this tool when you need **both** paths in one call: publisher transcripts where they exist (cheap, speaker-labelled, exact) and speech-to-text for everything else, with `transcriptSource` telling you which one you got.
- Choose it when you start from **what people actually share**: RSS feeds, Apple Podcasts show or episode links, episode web pages (the feed and audio are found for you) or direct file links.
- Choose it for **long episodes**: audio is re-encoded to 16 kHz mono and split into overlapping 10-minute chunks, then stitched on segment midpoints, so 2-3 hour shows work without size errors or duplicated lines at the joins.
- Choose it for **monitoring**: `onlyNewEpisodes` remembers what was delivered, so a scheduled run returns each new episode once.
- Choose it for **agent and RAG pipelines**: `llmText` (fillers and stutters removed), Markdown with linked timestamps, one combined `TRANSCRIPTS.md`, chapters when published.
- **Never charged:** invalid or unsupported links, feeds/files that can't be reached or decoded, audio with no speech, episodes skipped by caps, filters or monitor mode, and any failed episode.
- QA results: see "Tested" below.

**Choose a different tool when** you need speaker labels on speech-to-text output (diarization), translation to English, or Spotify-exclusive shows.

### Pricing (pay per event, no start fee)

| Event | Free | Bronze | Silver | Gold+ |
|---|---|---|---|---|
| Episode transcript (publisher) | $0.01 | $0.01 | $0.01 | $0.01 |
| Transcribed audio minute | $0.009 | $0.008 | $0.007 | $0.006 |

Minutes are rounded up once per episode (a 30 min 10 s episode = 31 minutes). A 60-minute episode without a publisher transcript costs $0.54 on Free. A feed with publisher transcripts costs $0.01 per episode, at any length.

### Input

| Field | Default | What it does |
|---|---|---|
| `sources` | (required) | Feeds, Apple links, episode pages, audio/video URLs |
| `maxEpisodesPerFeed` | 3 | Newest N per feed (0 = all) |
| `transcriptMode` | `auto` | `auto`, `publisherOnly`, `speechToText` |
| `maxAudioMinutes` | 120 | Per-run speech-to-text cap |
| `maxMinutesPerEpisode` / `truncateLongEpisodes` | 180 / false | Skip or truncate very long episodes |
| `onlyNewEpisodes` / `monitorId` | false | Monitor mode |
| `publishedAfter`, `titleFilter` | | Episode filters |
| `language` | auto | Publisher-transcript language and STT language hint |
| `vocabulary` | | Names/terms to spell correctly (show and episode titles always used) |
| `outputFormats` | all | text, segments, llmText, srt, vtt, markdown |
| `includeChapters` | true | Podcasting 2.0 chapters |

### Output example

```json
{ "status": "succeeded", "podcastTitle": "Podnews Daily", "episodeTitle": "WTF returns in visual form", "publishedAt": "2026-10-20T07:00:00.000Z",
  "durationSeconds": 356, "transcriptSource": "publisher", "publisherFormat": "vtt", "language": "en-gb", "wordCount": 880,
  "segments": [{ "start": 0, "end": 4.2, "text": "From our free daily newsletter..." }], "chargedEvent": "publisher-transcript", "charged": true }
```

The `OUTPUT` record summarises the run: counts, `audioMinutesCharged`, `errorTypes`, `stoppedBy`.

### Tested

Cloud-tested 20 Oct 2026 (build 1.0.8): 16/16 launch cases pass, across 11 podcast hosts and SRT, VTT, JSON and HTML transcripts in English, German and Spanish; Apple show and episode links; episode pages; spending caps; and invalid inputs. Charged events equalled delivered records in every run, and no failed row was charged.

- Speech-to-text word error rate against the publisher's own transcript: English 2.4% and 3.0%, Spanish 10.2%, German 16.9% (much of the gap is number spelling and errors in the reference).
- Long episodes: a 100-minute episode transcribes in about 25 seconds, with chunks cut at pauses.
- Misses: Spotify-only shows are not supported. Speech-to-text output has no speaker labels.

### FAQ

**Is the speech-to-text accurate?** It uses Whisper large-v3 (turbo as automatic fallback). See the measured word error rate under Tested. Names improve when you pass them in `vocabulary`.
**Do you store audio?** No. Audio is processed in the run's temporary storage and deleted when the episode is done.
**Copyright:** transcripts belong to the shows. Use them for research, search, accessibility and personal use; credit the show when quoting.

# Actor input Schema

## `sources` (type: `array`):

Podcast RSS feed URLs, Apple Podcasts show or episode links, episode web pages, or direct audio/video file URLs (mp3, m4a, mp4, wav...). Feeds return the newest episodes (see maxEpisodesPerFeed). Spotify and YouTube links are not supported. Example: \["https://feeds.buzzsprout.com/1.rss", "https://podcasts.apple.com/us/podcast/id1584274529"]

## `maxEpisodesPerFeed` (type: `integer`):

Newest N episodes taken from each feed or Apple show link. 0 = all episodes in the feed. Example: 5

## `transcriptMode` (type: `string`):

auto: use the publisher's Podcasting 2.0 transcript ($0.01 per episode) and transcribe only when none exists (per audio minute). publisherOnly: never run speech-to-text. speechToText: always transcribe.

## `maxAudioMinutes` (type: `integer`):

Hard cap on speech-to-text minutes billed in this run; episodes that would exceed it are skipped (not charged, retryable). 0 = publisher transcripts only. Combine with the run option maxTotalChargeUsd. Example: 300

## `maxMinutesPerEpisode` (type: `integer`):

Episodes longer than this are skipped (not charged), or transcribed only up to this length when truncateLongEpisodes is on. Example: 240

## `truncateLongEpisodes` (type: `boolean`):

When an episode is longer than maxMinutesPerEpisode, transcribe and bill only its first maxMinutesPerEpisode minutes (record flagged truncated: true) instead of skipping it.

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

Remember delivered episodes and skip them on later runs (never charged twice). Use with a schedule to get each new episode once.

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

Optional name for the onlyNewEpisodes memory, so several schedules can track the same feeds separately. Defaults to the list of sources. Example: "weekly-news-shows"

## `publishedAfter` (type: `string`):

Only episodes published on or after this date (YYYY-MM-DD). Example: "2026-10-01"

## `titleFilter` (type: `string`):

Only episodes whose title contains this text (case-insensitive). Example: "interview"

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

Optional ISO 639-1 code (en, es, de...). Picks the publisher transcript in that language and tells speech-to-text the spoken language. Empty = auto-detect (about 100 languages).

## `vocabulary` (type: `array`):

Guest names, brands and jargon passed to speech-to-text so they are spelled right. The show and episode titles are always used. Example: \["Adam Curry", "Podcasting 2.0", "Fountain"]

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

Fields to include per episode: text (paragraphs, speaker-labelled when known), segments (start/end seconds, speaker), llmText (fillers removed), srt, vtt, markdown (also combined in TRANSCRIPTS.md). Same price for any combination.

## `includeChapters` (type: `boolean`):

Add the episode's Podcasting 2.0 chapters (start, title) when the feed publishes them. Free.

## Actor input object example

```json
{
  "sources": [
    "https://podnews.net/rss"
  ],
  "maxEpisodesPerFeed": 1,
  "transcriptMode": "auto",
  "maxAudioMinutes": 120,
  "maxMinutesPerEpisode": 180,
  "truncateLongEpisodes": false,
  "onlyNewEpisodes": false,
  "outputFormats": [
    "text",
    "segments",
    "llmText",
    "srt",
    "vtt",
    "markdown"
  ],
  "includeChapters": true
}
```

# Actor output Schema

## `transcripts` (type: `string`):

Records with text, llmText, segments, SRT/VTT, Markdown, chapters and episode metadata.

## `summary` (type: `string`):

Counts, error types, audio minutes charged, stoppedBy.

## `markdown` (type: `string`):

All delivered transcripts in one Markdown file (when outputFormats includes markdown).

# 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 = {
    "sources": [
        "https://podnews.net/rss"
    ],
    "maxEpisodesPerFeed": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("catalyst-labs/podcast-transcript-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 = {
    "sources": ["https://podnews.net/rss"],
    "maxEpisodesPerFeed": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("catalyst-labs/podcast-transcript-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 '{
  "sources": [
    "https://podnews.net/rss"
  ],
  "maxEpisodesPerFeed": 1
}' |
apify call catalyst-labs/podcast-transcript-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,catalyst-labs/podcast-transcript-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/5jdK5z2K6EbJoWdZd/builds/cZTcV0iM37Fy2lx9g/openapi.json
