# Podcast Transcript & Episode Scraper - From RSS, No Audio (`that_red_bird/podcast-transcript-scraper`) Actor

Get podcast episodes with the transcripts publishers make public: reads RSS podcast:transcript files (SRT, VTT, JSON, HTML), transcript links in show notes, chapters, guests, sponsors and links. Search keywords across episodes. Not speech-to-text, no API key.

- **URL**: https://apify.com/that_red_bird/podcast-transcript-scraper.md
- **Developed by:** [mohamed alaya](https://apify.com/that_red_bird) (community)
- **Categories:** Videos, Social media, AI
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 feed scrapeds

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

## Podcast Transcript & Episode Scraper - from RSS, no audio models

Get podcast episodes **with the transcripts the publishers already made public**: text from `podcast:transcript` files
(SRT, VTT, JSON, HTML, plain text), transcript pages linked in the show notes, plus chapters, hosts and guests, sponsor reads,
links and a **keyword search across episodes**. Give it RSS URLs, Apple Podcasts links or just show names.

**Not speech-to-text.** This Actor never listens to audio. If a show publishes no transcript, the episode row says
`transcriptStatus: "none"` and explains it, instead of pretending. Coverage varies a lot by show - the `podcast` row tells you
how many of the returned episodes had one.

### What you get

A `podcast` row per show (title, author, hosts, categories, funding link, **transcript coverage %**) and an `episode` row per episode:

| Group | Fields |
|---|---|
| Episode | `title` - `publishedAt` - `episodeNumber` - `season` - `episodeType` - `duration` / `durationMinutes` - `audioUrl` - `link` - `explicit` - `image` - `guid` |
| **Transcript** | `transcriptStatus` (`published`, `published-via-show-notes-link`, `link-in-show-notes`, `tag-unreachable`, `available-not-fetched`, `none`) - `transcript` (text) - `transcriptFormat` - `transcriptUrl` - `transcriptLanguage` - `transcriptWordCount` - `transcriptSegments` (optional, with start/end/speaker) |
| People | `hosts` - `guests` with `guestsSource`: `podcast:person tags` (reliable) or *guessed from title/show notes (unverified)* |
| Structure | `chapters` (`podcast:chapters` file, or timestamp lists found in show notes, with `chaptersSource`) - `soundbites` |
| Notes | `showNotes` (plain text) - `links` (URLs with link text) - `sponsorMentions` (lines that read like sponsor reads, with links) |
| Search | `keywordMatches`: per keyword the count, where it was found (title / showNotes / transcript) and snippets with the time in the episode |

#### Which shows have transcripts?

Checked when this was written: **Podcasting 2.0** (SRT for every episode, chapters and guests), **Acquired** (text/VTT on recent
episodes), **The Changelog** (HTML transcript pages for part of its back catalogue). Many big publishers (NPR, NYT, Vox) publish none in their
feeds - you will see `none` for those, with chapters/guests/links still extracted.

#### Example

```json
{ "type": "episode", "podcastTitle": "Podcasting 2.0", "title": "Episode 273: \"Advertising is the Horse and Buggies of Podcasting\"",
  "publishedAt": "2026-10-02T00:00:00.000Z", "durationMinutes": 90, "hosts": ["Adam Curry", "Dave Jones"],
  "guests": [], "chaptersSource": "podcast:chapters", "chapters": [ { "startTime": 0, "title": "Intro" } ],
  "transcriptStatus": "published", "transcriptFormat": "srt", "transcriptWordCount": 13227,
  "transcript": "Adam Curry: ...", "keywordMatches": [ { "keyword": "podcast index", "count": 9, "foundIn": ["showNotes", "transcript"],
    "snippets": [ { "field": "transcript", "time": 460, "text": "…maybe the podcast index can benefit from that…" } ] } ] }
```

`time` is the start (in seconds) of the transcript paragraph containing the hit.

### Input

| Field | Default | Meaning |
|---|---|---|
| `feeds` | Podcasting 2.0 + Acquired | RSS URLs, Apple Podcasts links (`.../id123456789`) or show names (best Apple Podcasts match is used) |
| `maxEpisodesPerFeed` | 5 | Newest episodes returned per show |
| `keywords` | none | Keep only episodes mentioning a keyword in title, notes or transcript; adds `keywordMatches` |
| `maxEpisodesToScan` | 50 | With keywords: how many newest episodes per show are checked (their transcripts are downloaded) |
| `since`, `minDurationMinutes` | none | Date and length filters |
| `onlyEpisodesWithTranscript` | false | Skip episodes without a published transcript |
| `fetchTranscripts` / `followTranscriptLinks` | true / true | Download tagged transcripts; use transcript pages linked from show notes |
| `includeTranscriptText`, `includeTranscriptSegments`, `maxTranscriptChars` | true, false, 200000 | Output size controls |
| `fetchChapters`, `includeShowNotes` | true, true | Extras |

An empty input works: it returns the latest 5 episodes each of Podcasting 2.0 and Acquired, with full transcripts.

### Use cases

- **Search what shows said** about a company, product or topic across many shows, with context and timestamps.
- **Build a transcript corpus** for research, RAG or fine-tuning from shows that publish transcripts (`onlyEpisodesWithTranscript`).
- **Guest and sponsor research** for PR, booking and ad intelligence (guests from `podcast:person` tags, sponsor lines with links).
- **Content repurposing:** chapters, links and notes per episode for newsletters and show-note tools.
- **Feed for AI agents:** clean JSON per episode; works with the Apify API, MCP and LangChain loaders.

**Pipeline:** `podcast-transcript-scraper` (keywords + transcripts) -> your vector DB, Sheets or an LLM summariser.

### Pricing

Pay per event: **$0.002 per show read** (`feed-scraped`) and **$0.002 per episode returned** (`episode-scraped`), transcript
included - there is no extra charge for transcripts. Ten episodes of one show cost $0.022; the default empty-input run (2 shows, 5 episodes each) costs $0.024. Shows that cannot be read are not charged.

### FAQ

**Can it transcribe episodes that have no transcript?** No. It does not process audio. For those episodes you still get metadata,
chapters, links, guests and the audio URL to send to a speech-to-text service of your choice.

**What if a host blocks data-center IPs?** The Actor retries with other user agents and then through Apify's datacenter proxy. Hosts that block both will show up as an `error` row for that show.

**What about YouTube captions?** Not supported: YouTube blocks server-side caption downloads.

**How are guests found?** Reliable when the feed has `podcast:person` tags. Otherwise a pattern search over the title and first lines
of the show notes ("with", "feat.", "my guest is") fills `guests` and sets `guestsSource` to *guessed (unverified)*.

**How do I find a feed URL?** Pass the Apple Podcasts link or the show name and the Actor looks the feed up.

**Large feeds?** Feeds of 20 MB are read as a stream and reading stops as soon as enough episodes are found.

**Feedback:** open an issue on the Actor page; a short review on the Store page helps other podcast researchers find it.

### Related Actors

**reviews-theme-analyzer** - **app-reviews-scraper** - **event-scraper**.

# Actor input Schema

## `feeds` (type: `array`):

Podcast RSS feed URLs, Apple Podcasts links (podcasts.apple.com/.../id123456789) or plain show names (the best Apple Podcasts search match is used). The defaults are two shows that publish transcripts (Podcasting 2.0 and Acquired).

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

How many episodes to return per podcast (newest first). Each returned episode is one billable result.

## `keywords` (type: `array`):

Optional. Only episodes whose title, show notes or published transcript contain one of these words/phrases are returned, with context snippets (and the time in the episode when the transcript has timestamps). Case-insensitive.

## `maxEpisodesToScan` (type: `integer`):

Only used with keywords: how many of the newest episodes per podcast are checked (transcripts are downloaded for each) before the matching ones are returned.

## `since` (type: `string`):

ISO date, e.g. 2026-01-01. Older episodes are skipped. Leave empty for no limit.

## `minDurationMinutes` (type: `integer`):

Skip shorter episodes such as trailers. 0 = no minimum.

## `onlyEpisodesWithTranscript` (type: `boolean`):

Skip episodes without a published transcript. Useful to build a transcript corpus from mixed feeds.

## `fetchTranscripts` (type: `boolean`):

Download the transcript files that the feed lists (podcast:transcript tags) and turn them into text. Off = only report where a transcript is available.

## `followTranscriptLinks` (type: `boolean`):

When the feed has no transcript tag but the show notes link to a page named 'transcript', fetch that page and use its text if it is long enough to be a transcript.

## `includeTranscriptText` (type: `boolean`):

Put the full transcript text in each episode row. Turn off to get only status, URL and word count.

## `includeTranscriptSegments` (type: `boolean`):

Also output the transcript as segments with start time, end time and speaker (when the file has them). Makes rows larger.

## `maxTranscriptChars` (type: `integer`):

Longer transcripts are cut at this length in the output (transcriptTruncated is then true). Keyword search still reads the full transcript.

## `fetchChapters` (type: `boolean`):

Download podcast:chapters JSON files. Timestamp lists written in the show notes are used as chapters when no chapter file exists.

## `includeShowNotes` (type: `boolean`):

Include the episode description as plain text (first 8,000 characters). Links and sponsor mentions are extracted either way.

## `concurrency` (type: `integer`):

How many podcasts to process in parallel.

## Actor input object example

```json
{
  "feeds": [
    "https://feeds.podcastindex.org/pc20.xml",
    "https://feeds.transistor.fm/acquired"
  ],
  "maxEpisodesPerFeed": 5,
  "keywords": [],
  "maxEpisodesToScan": 50,
  "since": "",
  "minDurationMinutes": 0,
  "onlyEpisodesWithTranscript": false,
  "fetchTranscripts": true,
  "followTranscriptLinks": true,
  "includeTranscriptText": true,
  "includeTranscriptSegments": false,
  "maxTranscriptChars": 200000,
  "fetchChapters": true,
  "includeShowNotes": true,
  "concurrency": 3
}
```

# Actor output Schema

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

No description

## `downloadCsv` (type: `string`):

No description

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

No description

## `count` (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 = {
    "feeds": [
        "https://feeds.podcastindex.org/pc20.xml",
        "https://feeds.transistor.fm/acquired"
    ],
    "maxEpisodesPerFeed": 5,
    "keywords": [],
    "maxEpisodesToScan": 50,
    "since": "",
    "minDurationMinutes": 0,
    "onlyEpisodesWithTranscript": false,
    "fetchTranscripts": true,
    "followTranscriptLinks": true,
    "includeTranscriptText": true,
    "includeTranscriptSegments": false,
    "maxTranscriptChars": 200000,
    "fetchChapters": true,
    "includeShowNotes": true,
    "concurrency": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("that_red_bird/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 = {
    "feeds": [
        "https://feeds.podcastindex.org/pc20.xml",
        "https://feeds.transistor.fm/acquired",
    ],
    "maxEpisodesPerFeed": 5,
    "keywords": [],
    "maxEpisodesToScan": 50,
    "since": "",
    "minDurationMinutes": 0,
    "onlyEpisodesWithTranscript": False,
    "fetchTranscripts": True,
    "followTranscriptLinks": True,
    "includeTranscriptText": True,
    "includeTranscriptSegments": False,
    "maxTranscriptChars": 200000,
    "fetchChapters": True,
    "includeShowNotes": True,
    "concurrency": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("that_red_bird/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 '{
  "feeds": [
    "https://feeds.podcastindex.org/pc20.xml",
    "https://feeds.transistor.fm/acquired"
  ],
  "maxEpisodesPerFeed": 5,
  "keywords": [],
  "maxEpisodesToScan": 50,
  "since": "",
  "minDurationMinutes": 0,
  "onlyEpisodesWithTranscript": false,
  "fetchTranscripts": true,
  "followTranscriptLinks": true,
  "includeTranscriptText": true,
  "includeTranscriptSegments": false,
  "maxTranscriptChars": 200000,
  "fetchChapters": true,
  "includeShowNotes": true,
  "concurrency": 3
}' |
apify call that_red_bird/podcast-transcript-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,that_red_bird/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/3oQYLwbDCHKN7AFTc/builds/4lPOdzbrHoDq4ANHx/openapi.json
