# Podcast Scraper: RSS Episodes, Transcripts & Alerts (`stego-bot/podcast-tracker`) Actor

Podcast scraper for any public RSS feed, by feed URL or show name: show details, newest episodes with audio (MP3) links, transcript and chapter links, durations, publishing cadence and active status. Schedule it for new-episode alerts. No login or API key. JSON, CSV or Excel.

- **URL**: https://apify.com/stego-bot/podcast-tracker.md
- **Developed by:** [Stego](https://apify.com/stego-bot) (community)
- **Categories:** Social media, Marketing, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 show returneds

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 Scraper: RSS Episodes, Transcripts & New-Episode Alerts

**Podcast scraper** for any public podcast **RSS feed**, by feed URL or by show name. For each show you get one clean row with the show's details, how often it publishes, whether it is still active, and its latest episodes with **MP3 / audio links, transcript links and chapter links**. Turn on **Only new episodes** and schedule it to get **new-episode alerts**.

No login, no API key. The Actor reads each publisher's own public RSS feed. It does not scrape Apple Podcasts or Spotify, does not download audio, and does not transcribe anything: transcript links appear only when the publisher includes them in the feed.

### What can you use this podcast scraper for?

- **Monitor podcasts for new episodes:** schedule it daily and send only new episodes to Slack, email, Google Sheets or a webhook.
- **Research shows:** publishing cadence, days since the last episode and an *active* flag for a list of podcasts, e.g. for sponsorship or guest-booking research.
- **Build an episode database or feed an AI pipeline:** titles, dates, durations, descriptions, audio URLs and (where published) transcript links as flat JSON.

### What you get

**Per show**

- title, author, website, language, categories, explicit flag, cover image URL, short description
- feed URL (after redirects), `newFeedUrl` if the feed announces a move
- episodes in the feed, latest and oldest episode date, **days since the last episode**
- **publishing cadence**: median days between the newest 21 episodes
- **active** flag: a new episode within the last 90 days (you can change this) and the feed is not marked complete
- `podcastLocked` (podcast:locked), podcast GUID, **funding links** (podcast:funding)

**Per episode** (newest first, nested in the show row)

- title, publish date, duration in seconds, audio URL, type and size, episode page link
- season and episode numbers, episode type (full / trailer / bonus)
- **transcript links** (podcast:transcript, all formats the feed offers) and **chapters URL** (podcast:chapters)
- GUID, plain-text description (HTML removed, length you choose)

Transcripts and chapters appear only if the publisher puts them in the feed. Many big shows don't.

Want one row per episode instead? Open the **Episodes** view in the Output tab, or add `?view=episodes&skipEmpty=true` to the dataset items API URL. Each episode row also carries the show title and feed URL.

### How to use it

1. Paste feed URLs into **Podcast RSS feed URLs**, and/or show titles into **Podcast names**.
2. Set **Max episodes per show** (default 10; 0 = show details only).
3. Optional filters: only episodes since a date or from the last N days, keywords an episode must or must not mention, skip trailers and bonus episodes.
4. Run. Export as JSON, CSV, Excel, or use the API.

#### Finding a show by name

Names are matched against a built-in index of about 260,000 popular podcasts, built from the [Podcast Index](https://podcastindex.org) public data dump (snapshot date in the run summary). The best match is used; each row shows `nameMatch.matchedTitle`, whether it was an exact title match, and up to 3 alternatives with their feed URLs. Common titles can match the wrong show, so for important shows, use the feed URL. Brand-new or very small podcasts may not be in the index yet.

#### New-episode alerts (monitor mode)

Tick **Only new episodes since last run** and schedule the Actor (for example daily).

- The first time a show is seen, its current episodes are remembered and nothing is returned for it (untick *First run only saves a baseline* to also get the newest episodes on that first run; the rest of the back catalogue is still remembered, so later runs return only episodes published after it).
- After that, only episodes not returned before come back. Shows with nothing new produce no row and cost nothing.
- If more new episodes appear than *Max episodes per show*, the rest come on the next run.
- Memory lives in a named key-value store in your account (`podcast-tracker-state`). Use **State key** to run several separate monitors.

### Example input

```json
{
  "feedUrls": ["https://feeds.simplecast.com/54nAGcIl", "https://lexfridman.com/feed/podcast/"],
  "podcastNames": ["Hard Fork"],
  "maxEpisodesPerShow": 5,
  "episodesWithinDays": 30
}
```

### Example output (one show, shortened)

```json
{
  "status": "ok",
  "input": "Hard Fork",
  "nameMatch": {"query": "Hard Fork", "matchedTitle": "Hard Fork", "exactTitleMatch": true, "alternatives": [{"title": "Hard Fork Café", "feedUrl": "https://anchor.fm/s/4a793c64/podcast/rss"}]},
  "title": "Hard Fork",
  "author": "The New York Times",
  "feedUrl": "https://feeds.simplecast.com/l2i9YnTd",
  "language": "en",
  "categories": ["Technology"],
  "episodeCountInFeed": 222,
  "latestEpisodeDate": "2026-10-30T10:00:00Z",
  "daysSinceLastEpisode": 0.2,
  "medianDaysBetweenEpisodes": 7.0,
  "active": true,
  "episodes": [
    {"episodeTitle": "Are We in an A.I. Bubble? We're About to Find Out.", "publishedAt": "2026-10-30T10:00:00Z", "durationSeconds": 3261, "audioUrl": "https://…/default.mp3", "episodeNumber": 219, "episodeType": "full", "transcripts": [], "chaptersUrl": null}
  ]
}
```

A run summary (shows, episodes, errors, monitor status) is saved as `OUTPUT` in the run's key-value store.

### Broken or unreachable feeds

A feed that returns an error (404, 500, timeout, not a podcast feed, Atom instead of RSS, larger than 40 MB) gives a row with `status: "error"` and the reason. A name that can't be found gives `status: "not_found"`. An input that leads to a feed already returned in the same run gives `status: "duplicate"`. These rows are **free**, and the run carries on with the other shows. Slightly broken XML is read as far as possible and flagged in `feedWarnings`.

### Pricing

Pay per event, no subscription. The start fee is only $0.00005 per run ($0.05 per 1,000 runs):

| Event | Price |
|---|---|
| Actor start | $0.00005 per run |
| Show returned | $0.002 per show row |
| Episode returned | $0.0003 per episode ($0.30 per 1,000) |

Error, not-found and duplicate rows are free, and in monitor mode shows with nothing new are free. Each show is charged once per run: names that differ only in case or spacing count once, and a name or URL that leads to a feed already in the run gets a free `duplicate` row. If you set a *maximum charge per run*, the Actor stops cleanly at that limit and says so in the status and in the row (`episodesTruncatedByChargeLimit`). Delivery is crash-safe: if the platform restarts or migrates a run, shows already delivered are not delivered or charged again (and error rows are not repeated).

### Good to know

- **Row size:** a dataset item can be at most 9 MB. If a show's episodes (with long descriptions) would exceed about 8 MB, the row stops there, `episodesTruncatedByRowSize` is true and `moreEpisodesAvailable` is true. Only returned episodes are charged. Lower *Description length* to fit more.
- Big feeds are read one or two at a time to keep memory low; downloads still run in parallel.
- Data is only as good as each feed. Some publishers leave out durations, episode numbers or dates, and some feeds only list their newest episodes, so `episodeCountInFeed` can be lower than the show's real total.
- Times are UTC. "Days since last episode" is counted from the run time.
- Feeds are downloaded politely: at most 2 at once from the same host, with an honest User-Agent, timeouts and a short retry on server errors.
- **No personal contact data.** The Actor does not collect owner names or email addresses (`itunes:owner`, `managingEditor`, `webMaster`, the `podcast:locked` owner email) or podcast:person entries, and email addresses inside show notes are replaced with "\[email removed]". `author` is the public show byline from the feed.
- Audio files are not downloaded; you get their links.

### Source and credit

Show and episode data comes from each publisher's public podcast RSS feed (`feedUrl` in every row); content and rights stay with the publishers. Podcast-name lookup uses an index built from the Podcast Index public data dump (podcastindex.org), which Podcast Index allows to be downloaded, stored and redistributed; this Actor does not call the Podcast Index API. This Actor is not affiliated with or endorsed by Podcast Index, Apple Podcasts or any publisher.

### Use it from code, Zapier, Make, n8n or an AI agent

- **API:** start runs and read results through the [Apify API](https://docs.apify.com/api/v2) or the Python and JavaScript API clients. The **API** tab on this page has ready-made code.
- **No-code integrations:** connect the results to Zapier, Make, n8n, Google Sheets, Slack, email or a webhook with Apify's [integrations](https://docs.apify.com/platform/integrations).
- **AI agents (MCP):** add this Actor as a tool through the [Apify MCP server](https://docs.apify.com/mcp), e.g. `https://mcp.apify.com?tools=stego-bot/podcast-tracker`. Input fields and output fields are fully described, so an agent can fill the input and read the results without guessing.
- **Schedules:** add an Apify schedule (e.g. daily) to turn a saved input into a recurring job or alert.

### FAQ

**Does it work with Apple Podcasts or Spotify links?** It reads RSS feeds. Paste the show's RSS feed URL, or type the show name and let the built-in index find the feed.

**Does it transcribe episodes?** No. It returns transcript links only when the publisher publishes them in the feed (podcast:transcript).

**Do I need an API key?** No.

### More Actors from stego-bot

- [Bulk DNS Lookup & Domain Availability Checker](https://apify.com/stego-bot/rdap-domain-lookup)
- [EU Tenders Scraper (TED): Public Procurement Search](https://apify.com/stego-bot/ted-tenders)
- [SAM.gov Contract Opportunities API & Bid Alerts](https://apify.com/stego-bot/samgov-opportunities)
- [Greenhouse & Lever Jobs Scraper API + Job Alerts](https://apify.com/stego-bot/ats-jobs)

# Actor input Schema

## `feedUrls` (type: `array`):

Public RSS feed URLs of the podcasts to check (one per line). feed:// and itpc:// links are accepted. Most reliable input.

## `podcastNames` (type: `array`):

Show titles to look up, e.g. "Hard Fork". Each name is matched to one feed in a built-in index of about 260,000 popular podcasts (from the Podcast Index public data dump). Each row shows the matched title and up to 3 alternatives; if the match is wrong, use the feed URL instead. Names that differ only in upper/lower case or spacing count once; a name that points to a feed already in this run gives a free "duplicate" row.

## `maxEpisodesPerShow` (type: `integer`):

Newest episodes to return for each show (after filters). 0 = show details only, no episodes. Each returned episode is a billable event. Very large rows are trimmed to stay under the 9 MB dataset item limit (episodesTruncatedByRowSize).

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

Skip episodes published before this date (YYYY-MM-DD). Episodes without a publish date are skipped when this is set.

## `episodesWithinDays` (type: `integer`):

Alternative to the date above: keep only episodes published in the last N days. 0 or empty = no limit.

## `includeKeywords` (type: `array`):

Keep only episodes whose title or description contains at least one of these words or phrases (case-insensitive).

## `excludeKeywords` (type: `array`):

Drop episodes whose title or description contains any of these words or phrases (case-insensitive).

## `skipTrailersAndBonus` (type: `boolean`):

Drop episodes the feed marks as itunes:episodeType trailer or bonus.

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

Monitor mode: return only episodes not returned before (remembered per show in a named key-value store). Shows with nothing new produce no row and no charge. Schedule the Actor (e.g. daily) to get new-episode alerts.

## `baselineOnFirstRun` (type: `boolean`):

In monitor mode, the first time a show is seen its current episodes are remembered and nothing is returned for it, so later runs return only truly new episodes. Untick to also get the current newest episodes (up to "Max episodes per show") on the first run; the rest of the back catalogue is remembered as seen either way.

## `stateKey` (type: `string`):

Name of this monitor (letters, digits, "-"). Use different keys to run several independent monitors. Default: the Apify task ID, or "default".

## `stateStoreName` (type: `string`):

Named key-value store in your account where monitor mode remembers delivered episodes.

## `descriptionMaxLength` (type: `integer`):

Maximum characters of the plain-text show and episode descriptions (HTML removed). 0 = leave descriptions out.

## `activeWithinDays` (type: `integer`):

A show is marked active: true when its newest episode is at most this many days old (and the feed is not marked complete).

## `maxConcurrency` (type: `integer`):

How many feeds to download at the same time (never more than 2 from the same host).

## Actor input object example

```json
{
  "feedUrls": [
    "https://feeds.simplecast.com/54nAGcIl",
    "https://feeds.megaphone.fm/hubermanlab"
  ],
  "podcastNames": [
    "Hard Fork"
  ],
  "maxEpisodesPerShow": 5,
  "skipTrailersAndBonus": false,
  "onlyNew": false,
  "baselineOnFirstRun": true,
  "stateStoreName": "podcast-tracker-state",
  "descriptionMaxLength": 300,
  "activeWithinDays": 90,
  "maxConcurrency": 5
}
```

# Actor output Schema

## `shows` (type: `string`):

Dataset with one item per podcast: show details, activity stats and nested episodes.

## `episodes` (type: `string`):

Same dataset, unwound into one row per episode with the show title and feed URL.

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

OUTPUT record with counts of shows, episodes, errors and monitor status for this run.

# 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 = {
    "feedUrls": [
        "https://feeds.simplecast.com/54nAGcIl",
        "https://feeds.megaphone.fm/hubermanlab"
    ],
    "podcastNames": [
        "Hard Fork"
    ],
    "maxEpisodesPerShow": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("stego-bot/podcast-tracker").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 = {
    "feedUrls": [
        "https://feeds.simplecast.com/54nAGcIl",
        "https://feeds.megaphone.fm/hubermanlab",
    ],
    "podcastNames": ["Hard Fork"],
    "maxEpisodesPerShow": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("stego-bot/podcast-tracker").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 '{
  "feedUrls": [
    "https://feeds.simplecast.com/54nAGcIl",
    "https://feeds.megaphone.fm/hubermanlab"
  ],
  "podcastNames": [
    "Hard Fork"
  ],
  "maxEpisodesPerShow": 5
}' |
apify call stego-bot/podcast-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,stego-bot/podcast-tracker"
        }
    }
}
```

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/LgBUxJ9F0gvK9e7Co/builds/vnTgQLb1aZEhKMqag/openapi.json
