# Podcast Transcript Scraper, Audio Transcriber, RSS and Apple (`george.the.developer/podcast-transcript-scraper`) Actor

Turn public podcast RSS feeds, Apple Podcasts show URLs or audio and video file links into plain text transcripts and timestamped segments with CPU Whisper for audio to text. No podcast login or transcription API key. Pay per transcribed minute.

- **URL**: https://apify.com/george.the.developer/podcast-transcript-scraper.md
- **Developed by:** [George Kioko](https://apify.com/george.the.developer) (community)
- **Categories:** Videos, AI
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $9.60 / 1,000 transcribed 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

Podcast and Audio Transcriber is an Apify Actor that converts public podcast episodes from RSS feeds or Apple Podcasts show URLs and direct audio or video file links into plain text transcripts and optional timestamped segments without a podcast login or transcription API key.

**No podcast login. No transcription API key. CPU transcription inside the Actor.** Researchers and content teams can use **podcast transcription**, **RSS transcript scraping** and **Apple Podcasts transcripts** to turn spoken audio into structured episode rows.

Only a delivered transcript containing at least 20 characters qualifies for minute charges. Failed downloads, nonaudio responses and empty or shorter transcripts produce no row and no transcript charge.

### Pricing

Prices are per event. You pay only for audio that was turned into a transcript row.

| Event | Configured price | You pay when |
| --- | --- | --- |
| `apify-actor-start` | $0.00005 | The platform records its synthetic start event |
| `transcript-minute` | $0.012 per started audio minute | A qualifying transcript row has been delivered |

**The transcript price is $0.72 per hour of transcribed audio.** Duration rounds up separately for each episode. A 280 second episode counts as five minutes and costs $0.06 in transcript events, plus the platform start event. Many short episodes can cost more than $0.72 per combined hour because each rounds up.

Local and free runs without pay per event pricing deliver rows with `charged` set to false. The start event is managed by the platform and never charged by Actor code. The minute charge counts the audio processed, including silence, rather than CPU wall time or only spoken segments.

### Public podcast transcription without a separate service

Supply public RSS or Apple Podcasts show URLs. Transcription uses faster-whisper on CPU inside the Actor. The default `base` model is downloaded when the Docker image is built, so default runs load it from disk.

```json
{
  "podcasts": ["https://feeds.npr.org/500005/podcast.xml"],
  "maxEpisodes": 1,
  "maxMinutesPerEpisode": 10,
  "model": "base",
  "includeSegments": true
}
```

`tiny` favors speed and `small` offers a larger model with greater CPU cost. Those optional models download on first use and may add startup time.

### Audio and video file links

Supply up to twenty public HTTP or HTTPS file links in `audioUrls` for audio to text. Supported formats include mp3, m4a, wav, ogg, flac, mp4, webm and mov. Video files contribute their audio track. Each file is one item with the same duration cap and delivery rules as a podcast episode. Podcasts are processed first when both inputs are supplied.

```json
{
  "audioUrls": ["https://example.com/interview.mp4"],
  "maxMinutesPerEpisode": 10,
  "includeSegments": true
}
```

File rows have `sourceType` set to `file`, empty `podcastTitle` and `feedUrl`, and null `publishedAt`. The URL path supplies `episodeTitle` and the full URL supplies `episodeGuid` and `audioUrl`.

### How it works

1. Resolve Apple show IDs through the public iTunes lookup endpoint, or read the supplied RSS feed directly.
2. Select audio enclosures newest first, up to `maxEpisodes` for each podcast.
3. Follow media redirects with a browser User-Agent and accept audio, video, generic binary or missing content types. Reject text and JSON responses. Downloads are capped at 200 MB.
4. Use ffprobe to measure audio and ffmpeg to convert only the first `maxMinutesPerEpisode` minutes to 16 kHz mono WAV.
5. Transcribe with four CPU threads, int8 computation, beam size one and voice activity detection.
6. Deliver a qualifying row first, then charge the rounded-up audio minutes. Stop cleanly when the remaining charge allowance cannot cover an episode.

No new episode starts within 90 seconds of the run timeout. Before transcription the charge allowance is checked against the prepared audio duration. If an episode cannot fit the allowance, the run stops instead of processing only an affordable part.

Apple episode links with `?i=` select only the newest RSS episode. Apple episode IDs are not reliably matched to RSS GUIDs or titles, so this Actor does not promise the linked episode.

### What data does it extract?

Each episode or file row contains `sourceType`, `podcastTitle`, `feedUrl`, `episodeTitle`, `episodeGuid`, `publishedAt`, `audioUrl`, `audioDurationSec`, `transcribedSec`, `truncated`, `language`, `languageProbability`, `model`, `transcript`, `wordCount`, `scrapedAt` and `charged`. Podcast rows have `sourceType` set to `podcast`.

`segments` contains `start`, `end` and `text` when `includeSegments` is true. Times are seconds from the beginning of the episode. Publication dates are null when missing. `audioDurationSec` uses feed metadata when present and ffprobe otherwise. `transcribedSec` measures the prepared audio actually sent to Whisper. `truncated` uses the measured source duration.

`charged` identifies a row submitted for paid minute charging. Dataset delivery precedes charging, so an exceptional charge failure can leave a delivered row marked true. The run logs the failure and stops. The platform charge record is authoritative.

### What is NOT returned

- Speaker names, speaker identification or separate speaker tracks.
- Private feeds, login-protected episodes or anything behind a paywall.
- Video frames or downloaded media files.
- Audio beyond the first `maxMinutesPerEpisode` minutes.
- A guaranteed transcript of the specific episode referenced by an Apple episode ID.
- Human-verified text, perfect punctuation or guaranteed spelling of names.

### Start a run

1. Open the Actor and keep the prefilled NPR feed, one episode and a ten-minute cap.
2. Select a language or leave it empty for automatic detection.
3. Start the run and read the default dataset when it finishes.
4. Export rows as JSON, CSV or Excel.

The prefilled input selects one episode. The general defaults select up to three episodes per podcast and cap each at 60 minutes. The default run allocates 4096 MB and a 3600-second timeout.

### Input

```json
{
  "podcasts": ["https://podcasts.apple.com/us/podcast/npr-news-now/id121493675"],
  "maxEpisodes": 3,
  "maxMinutesPerEpisode": 60,
  "model": "base",
  "language": "en",
  "includeSegments": true
}
```

| Field | Type | Default | Meaning |
| --- | --- | --- | --- |
| `podcasts` | string array | Optional, prefilled NPR feed | Zero to ten public RSS or Apple Podcasts URLs |
| `audioUrls` | string array | Optional, empty | Zero to twenty public audio or video file URLs |
| `maxEpisodes` | integer | 3, prefill 1 | Newest episodes per podcast, maximum 50 |
| `maxMinutesPerEpisode` | integer | 60, prefill 10 | First N minutes only, maximum 240 |
| `model` | enum | `base` | `tiny`, `base` or `small` |
| `language` | string | Empty | Lowercase ISO 639-1 code, or automatic detection |
| `includeSegments` | boolean | true | Include timestamped segments |

At least one of `podcasts` or `audioUrls` must be non empty. `maxEpisodes` applies only to podcasts. `maxMinutesPerEpisode` applies to each episode or file.

### Output

This complete row comes from an offline test using the supplied NPR RSS metadata and sample audio fixture with a one-minute cap. It is an actual local transcription with free-run delivery. The sample audio is longer than the feed duration, so the row preserves feed metadata while measuring the transcription cap independently.

```json
{
  "sourceType": "podcast",
  "podcastTitle": "NPR News Now",
  "feedUrl": "https://feeds.npr.org/500005/podcast.xml",
  "episodeTitle": "2am ET, October 06 | The latest headlines from NPR",
  "episodeGuid": "9fdf9910-5b0a-499c-b5ae-780ff78cbb0e",
  "publishedAt": "2026-10-06T06:09:50+00:00",
  "audioUrl": "https://prfx.byspotify.com/e/play.podtrac.com/npr-500005/npr.simplecastaudio.com/368f8510-314e-46f1-8d26-5b87ed6ab6eb/episodes/4c6fe20f-5d14-4a4b-b807-2bb26505b888/audio/128/default.mp3?awCollectionId=368f8510-314e-46f1-8d26-5b87ed6ab6eb&awEpisodeId=4c6fe20f-5d14-4a4b-b807-2bb26505b888&feed=O9WlY7a5&t=podcast&e=nx-s1-20261006-0200-long&p=500005&d=280&size=4585474",
  "audioDurationSec": 280.0,
  "transcript": "This is NPR News Now. The latest headlines every hour. Live from NPR News, I'm child Snyder. President Trump is back at the White House after he signed an executive order named at lowering diesel fuel costs. Trump signed the order during a Monday evening campaign rally in Nebraska as NPR's Franco Ordonia's reports. President Trump told the audience in the middle of agriculture country that he was signing the order to help farmers. The rising cost of fuel has been a significant challenge for Republicans heading into the midterms. Prices for diesel used by trucks have been hit particularly hard due to the wars in both Iran and Ukraine. The president did not share details but the order is expected to expand access to diesel, including so-called red dye diesel fuel which is used by the agriculture industry and not subject to the same state and federal highway taxes as regular diesel. A number of states, including Texas.",
  "segments": [
    {
      "start": 0.0,
      "end": 4.4,
      "text": "This is NPR News Now."
    },
    {
      "start": 4.4,
      "end": 7.28,
      "text": "The latest headlines every hour."
    },
    {
      "start": 7.28,
      "end": 11.08,
      "text": "Live from NPR News, I'm child Snyder."
    },
    {
      "start": 11.08,
      "end": 15.8,
      "text": "President Trump is back at the White House after he signed an executive order named at"
    },
    {
      "start": 15.8,
      "end": 18.24,
      "text": "lowering diesel fuel costs."
    },
    {
      "start": 18.24,
      "end": 23.36,
      "text": "Trump signed the order during a Monday evening campaign rally in Nebraska as NPR's Franco"
    },
    {
      "start": 23.36,
      "end": 24.84,
      "text": "Ordonia's reports."
    },
    {
      "start": 24.84,
      "end": 28.8,
      "text": "President Trump told the audience in the middle of agriculture country that he was signing the"
    },
    {
      "start": 28.8,
      "end": 30.64,
      "text": "order to help farmers."
    },
    {
      "start": 30.64,
      "end": 36.32,
      "text": "The rising cost of fuel has been a significant challenge for Republicans heading into the midterms."
    },
    {
      "start": 36.32,
      "end": 40.88,
      "text": "Prices for diesel used by trucks have been hit particularly hard due to the wars in"
    },
    {
      "start": 40.88,
      "end": 43.2,
      "text": "both Iran and Ukraine."
    },
    {
      "start": 43.2,
      "end": 48.44,
      "text": "The president did not share details but the order is expected to expand access to diesel,"
    },
    {
      "start": 48.44,
      "end": 53.76,
      "text": "including so-called red dye diesel fuel which is used by the agriculture industry and not"
    },
    {
      "start": 53.76,
      "end": 58.12,
      "text": "subject to the same state and federal highway taxes as regular diesel."
    },
    {
      "start": 58.12,
      "end": 60.0,
      "text": "A number of states, including Texas."
    }
  ],
  "language": "en",
  "languageProbability": 0.9997122883796692,
  "transcribedSec": 60.0,
  "truncated": true,
  "model": "base",
  "wordCount": 159,
  "scrapedAt": "2026-10-06T06:50:00.667370+00:00",
  "charged": false
}
```

### Use from Claude, ChatGPT and any MCP agent

Add it through the Apify MCP server and ask your agent to transcribe the newest episodes from a public feed.

```text
https://mcp.apify.com/?tools=george.the.developer/podcast-transcript-scraper
```

From Python with an Apify token for platform access.

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("george.the.developer/podcast-transcript-scraper").call(
    run_input={
        "podcasts": ["https://feeds.npr.org/500005/podcast.xml"],
        "maxEpisodes": 1,
        "maxMinutesPerEpisode": 10,
    }
)
rows = client.dataset(run.default_dataset_id).list_items().items
print(rows)
```

With curl, wait for the run and return the dataset rows.

```bash
curl -X POST "https://api.apify.com/v2/acts/george.the.developer~podcast-transcript-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"podcasts":["https://feeds.npr.org/500005/podcast.xml"],"maxEpisodes":1,"maxMinutesPerEpisode":10}'
```

An Apify token authenticates platform access. No Apple, podcast host or external transcription credential is needed.

### Integrations

**Clay.** Use `https://api.apify.com/v2/datasets/DATASET_ID/items?format=json` as an HTTP enrichment source and map `episodeTitle`, `transcript`, `language` and `feedUrl` to columns.

**n8n and Make.** Select the Actor in an Apify node or module, enter feed URLs and read the default dataset in the next step.

**Google Sheets.** Export rows as CSV or use the Apify Google Sheets integration. JSON preserves nested timestamped segments.

### Use cases

- **Researchers** collect transcripts from selected public feeds and retain episode GUIDs and source links.
- **Content teams** review timestamped passages before preparing episode summaries.
- **Search builders** index plain text with podcast titles and publication dates.
- **AI agents** retrieve transcript rows through MCP and cite the original episode metadata.

### FAQ

#### How accurate is transcription?

Whisper base on CPU produces automated text and English works best. Names, accents, background noise and overlapping speech can cause errors. Language probability estimates language detection, not transcript correctness. Review passages before quoting them.

#### Does an Apple episode link select that exact episode?

No. A link with `?i=` selects the newest RSS episode only. Use a show URL for several newest episodes. The Apple episode identifier is not mapped to an RSS GUID.

#### Will the whole episode be transcribed?

Only when it fits `maxMinutesPerEpisode`. Longer audio is trimmed before transcription and marked `truncated` true. The duration cap applies to each episode separately.

#### What happens when a download or transcription fails?

The episode is skipped with a log line and no transcript minute charge. A nonaudio response or fewer than 20 transcript characters produces no dataset row. A failed dataset push never triggers a minute charge.

#### How fast is it?

On Apify with the base model and 4 GB of memory, a 5.3 minute news episode finished in 75 to 97 seconds per run on October 6, 2026, including download, model start and transcription. Longer episodes take longer in proportion. Downloads, CPU contention and model choice affect total time.

#### Is an API key needed?

No transcription or podcast API key is needed. Apify API and MCP access require platform authentication. The default model is bundled in the built image. Optional models need access to download their weights.

#### Can I get speaker labels?

No. The Actor does not return speaker names, speaker identification or separate speaker tracks. Each row has the plain transcript and, when `includeSegments` is true, timestamped segments with `start`, `end` and `text`.

#### Can an AI agent call this actor?

Yes. Add it through the Apify MCP server and ask your agent to transcribe the newest episodes from a public feed. Podcast rows carry the episode title, feed URL, publish date and transcript, so the agent can cite the source episode. It also runs from Python with the Apify client or from curl through the Apify API.

# Actor input Schema

## `podcasts` (type: `array`):

Public RSS feed or Apple Podcasts show URLs, at most ten. Apple episode URLs select the newest RSS episode. Provide at least one podcast or audioUrls link.

## `audioUrls` (type: `array`):

Up to twenty public HTTP or HTTPS file links for audio to text, including mp3, m4a, wav, ogg, flac, mp4, webm and mov. Example https://example.com/interview.mp3. Provide at least one podcast or audioUrls link.

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

Select up to this many episodes per podcast, newest first.

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

Only the first N minutes are transcribed. Longer episodes are marked truncated.

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

Base is cached in the image. Tiny favors speed. Small uses more CPU and downloads on first use.

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

Optional lowercase ISO 639-1 language code. Empty means automatic detection.

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

Include start, end and text for each transcript segment.

## Actor input object example

```json
{
  "podcasts": [
    "https://feeds.npr.org/500005/podcast.xml"
  ],
  "maxEpisodes": 1,
  "maxMinutesPerEpisode": 10,
  "model": "base",
  "language": "",
  "includeSegments": true
}
```

# Actor output Schema

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

One row per successfully transcribed episode with metadata, plain text, optional timestamped segments, duration and billing status.

# 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 = {
    "podcasts": [
        "https://feeds.npr.org/500005/podcast.xml"
    ],
    "maxEpisodes": 1,
    "maxMinutesPerEpisode": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("george.the.developer/podcast-transcript-scraper").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 = {
    "podcasts": ["https://feeds.npr.org/500005/podcast.xml"],
    "maxEpisodes": 1,
    "maxMinutesPerEpisode": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("george.the.developer/podcast-transcript-scraper").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 '{
  "podcasts": [
    "https://feeds.npr.org/500005/podcast.xml"
  ],
  "maxEpisodes": 1,
  "maxMinutesPerEpisode": 10
}' |
apify call george.the.developer/podcast-transcript-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,george.the.developer/podcast-transcript-scraper"
        }
    }
}
```

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/Yre3cI5F3jv62PqFM/builds/tfNbChqEEUTp9DI89/openapi.json
