# Podcast Scraper: Apple Podcasts Search, Charts & RSS Episodes (`tidyharvest/podcast-scraper`) Actor

Search Apple Podcasts, look up shows by link or id, or pull the Top Shows chart per country; get publisher, feed URL, genres, rating and the newest episodes with audio URLs, durations and descriptions. No proxy, no start fee. $0.90 per 1,000 podcasts, $0.40 per 1,000 episodes.

- **URL**: https://apify.com/tidyharvest/podcast-scraper.md
- **Developed by:** [TidyHarvest](https://apify.com/tidyharvest) (community)
- **Categories:** Social media, AI
- **Stats:** 2 total users, 1 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.
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 Scraper: Apple Podcasts Search, Charts & RSS Episodes

Get **podcasts and their episodes** as clean structured data. Search Apple Podcasts by keyword, look up shows by **Apple Podcasts link or id**, pull Apple's **Top Shows chart** for any country, or give any **RSS feed URL**. Every podcast row has **name, publisher, RSS feed URL, genres, episode count, artwork, explicit flag, language, last release date** and (optionally) the **Apple star rating**. With episodes on, the actor reads each show's public RSS feed and returns its newest episodes: **title, publish date, duration, audio file URL, description, season and episode numbers, GUID**.

It uses the documented **iTunes Search API**, Apple's public chart feeds and each publisher's own RSS feed. **No browser, no proxy, no login or API key.** Two prices: **$0.90 per 1,000 podcasts** and **$0.40 per 1,000 episodes** (lower on paid Apify plans), no start fee.

### What you can do with it

- **Podcast guest booking and PR outreach lists:** find every show on a topic with its publisher, website, genres and how recently it published.
- **Ad sales and sponsorship research:** pull the Top Shows chart per country and see category, size (episode count) and rating.
- **Transcription and AI pipelines:** get direct audio URLs, durations and descriptions for the newest episodes of a list of shows (and `transcriptUrl` when the publisher provides one).
- **Monitoring:** run on a schedule with `episodesSince` to collect only new episodes from the shows you follow.
- **Market and content research:** compare publishing cadence, episode length and topics across a niche.

### Input

| Field | What it does |
|---|---|
| `searchTerms` | Keywords, one per line (`true crime`, `startup interviews`). |
| `podcasts` | Apple Podcasts links, Apple ids, or any public RSS feed URL. |
| `chartCountries` | Add Apple's Top Shows chart for these countries (`us`, `gb`, `de`...); `chartLimit` = how many (max 100). |
| `country` | Apple store country for search and id lookups. Default `us`. |
| `maxResultsPerSearch` | Podcasts per search term (max 200). Default 20. |
| `maxPodcasts` | Hard cap on podcast rows for the run (caps cost). |
| `includeEpisodes` | Read each show's RSS feed for episodes and feed details. Default on. |
| `maxEpisodesPerPodcast` | Newest N episodes per show. Default 10; 0 = feed details only. |
| `episodesSince` | Only episodes published on or after this date (`YYYY-MM-DD`). |
| `episodeKeywords` | Keep only episodes whose title or description contains one of these words. |
| `includeRating` | Add the Apple star rating and rating count (one extra page load per show). |
| `includeOwnerContact` | Add the owner name and email the publisher lists in its own feed (`ownerName`, `ownerEmail`). Default on; needs episodes on. |

Example:

```json
{ "searchTerms": ["artificial intelligence"], "chartCountries": ["us"], "chartLimit": 50,
  "maxEpisodesPerPodcast": 5, "episodesSince": "2026-09-01", "includeRating": true }
```

### Output

One dataset, two row types (`type`). Use the **Podcasts** or **Episodes** view, or filter on `type`.

Podcast:

```json
{
  "type": "podcast",
  "podcastId": "1200361736",
  "name": "The Daily",
  "author": "The New York Times",
  "feedUrl": "https://feeds.simplecast.com/Sl5CSM3S",
  "appleUrl": "https://podcasts.apple.com/us/podcast/the-daily/id1200361736",
  "primaryGenre": "Daily News",
  "genres": ["Daily News", "News"],
  "episodeCount": 2750,
  "lastReleaseDate": "2026-10-15T09:52:00Z",
  "explicit": false,
  "contentAdvisoryRating": "Clean",
  "country": "USA",
  "artworkUrl": "https://is1-ssl.mzstatic.com/image/thumb/.../600x600bb.jpg",
  "language": "en",
  "description": "This is what the news should sound like. ...",
  "website": "https://www.nytimes.com/the-daily",
  "showType": "episodic",
  "feedEpisodeCount": 65,
  "lastEpisodeDate": "2026-10-15T09:52:16Z",
  "ownerName": "The New York Times",
  "ownerEmail": "...@nytimes.com",
  "rating": 4.3,
  "ratingCount": 105934,
  "feedError": null,
  "source": "lookup",
  "scrapedAt": "2026-10-15T22:54:21Z"
}
```

Episode:

```json
{
  "type": "episode",
  "podcastId": "1200361736",
  "podcastName": "The Daily",
  "title": "The Republican Strategy to Salvage the Midterms",
  "guid": "db93ab61-641a-4cb8-9067-6b5498c8b8d5",
  "publishedAt": "2026-10-15T09:52:16Z",
  "durationSeconds": 2030,
  "audioUrl": "https://dts.podtrac.com/redirect.mp3/.../default.mp3",
  "audioType": "audio/mpeg",
  "audioSizeBytes": 32490640,
  "seasonNumber": null,
  "episodeNumber": null,
  "episodeType": "full",
  "explicit": false,
  "link": "https://www.nytimes.com/the-daily",
  "imageUrl": "https://image.simplecastcdn.com/...jpg",
  "transcriptUrl": null,
  "description": "With Republicans trailing in the polls, ...",
  "feedUrl": "https://feeds.simplecast.com/Sl5CSM3S",
  "scrapedAt": "2026-10-15T22:54:21Z"
}
```

Search rows also carry `searchTerm` and `searchRank`; chart rows carry `chartCountry` and `chartRank`. `episodeCount` is Apple's count; `feedEpisodeCount` is how many episodes the RSS feed currently lists (many publishers keep only the latest ones in the feed).

### How to use

1. Enter search terms, Apple links/ids or feed URLs, and/or chart countries.
2. Choose how many episodes per show you want (or switch episodes off for directory data only).
3. Run, then download the dataset as JSON, CSV or Excel, or connect it to Sheets, Make, Zapier or your own code through the Apify API.

### Pricing

Pay per result, no start fee:

| Plan | Podcast (`podcast-scraped`) | Episode (`episode-scraped`) |
|---|---|---|
| Free | $0.90 / 1,000 | $0.40 / 1,000 |
| Bronze | $0.80 / 1,000 | $0.35 / 1,000 |
| Silver | $0.60 / 1,000 | $0.28 / 1,000 |
| Gold | $0.45 / 1,000 | $0.20 / 1,000 |
| Platinum | $0.30 / 1,000 | $0.15 / 1,000 |
| Diamond | $0.20 / 1,000 | $0.10 / 1,000 |

The rating and feed details are part of the podcast row and cost nothing extra. `maxPodcasts`, `maxEpisodesPerPodcast`, `episodesSince` and `episodeKeywords` apply **before** you are charged. A run that finds no podcast at all (no search hits, unknown ids, unreadable feeds) fails with a clear message instead of returning an empty dataset.

### Limits and notes

- Apple's search returns at most 200 shows per term and asks for about 20 requests a minute, so the actor paces its Apple calls (about 3 seconds apart); chart and id lookups are batched, so this matters only for many search terms.
- Apple's Top Shows chart goes up to 100 per country; Apple does not publish one for every country.
- Episodes come from each publisher's RSS feed, newest first. Some feeds list only recent episodes. Shows without a public feed (Apple-exclusive or subscriber-only) get a `feedError` and no episodes; a feed that can't be read or parsed is recorded in `feedError` and does not fail the run.
- Audio URLs point at the publisher's host (often through tracking redirects). This actor does not download or transcribe audio.
- `ownerName`/`ownerEmail` are what the publisher lists in its own public feed for podcast directories (often a network or hosting-platform forwarding address). They can identify a person: use them under the privacy and anti-spam rules that apply to you (GDPR, CAN-SPAM), or turn the option off.
- Independent tool, **not affiliated with or endorsed by Apple.** Apple Podcasts is a trademark of Apple Inc. Podcast content belongs to its publishers; respect their rights when reusing descriptions, artwork or audio.

# Actor input Schema

## `searchTerms` (type: `array`):

Find podcasts by keyword, one per line (same search as Apple Podcasts: matches show titles, publishers and topics).

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

Specific shows, one per line: an Apple Podcasts link (`https://podcasts.apple.com/us/podcast/the-daily/id1200361736`), the numeric Apple id (`1200361736`), or any public RSS feed URL (works for shows not listed on Apple too).

## `chartCountries` (type: `array`):

Add Apple's current Top Shows chart for these countries (2-letter codes: `us`, `gb`, `de`, `ca`, ...). Each row gets `chartRank`.

## `chartLimit` (type: `integer`):

How many shows to take from each chart (Apple publishes up to 100).

## `country` (type: `string`):

2-letter store country for search and id lookups (`us`, `gb`, `de`, `fr`, `jp`, ...). Apple links carry their own country.

## `maxResultsPerSearch` (type: `integer`):

Apple returns at most 200 shows per search.

## `maxPodcasts` (type: `integer`):

Hard cap on podcast rows for the whole run (also caps your cost). 0 or empty = no limit.

## `includeEpisodes` (type: `boolean`):

Reads each podcast's public RSS feed: adds episode rows plus the show's description, language, website and feed episode count. Off = Apple directory data only (faster, podcast rows only).

## `maxEpisodesPerPodcast` (type: `integer`):

Newest episodes first. 0 = no episode rows but still enrich the podcast row from its feed.

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

Skip older episodes (not charged).

## `episodeKeywords` (type: `array`):

Keep an episode only if its title or description contains one of these (case-insensitive). Empty = all. Filtered episodes are not charged.

## `includeRating` (type: `boolean`):

Adds `rating` (1-5) and `ratingCount` from the public Apple Podcasts show page. One extra page load per podcast, so slower.

## `includeOwnerContact` (type: `boolean`):

Add the contact the podcast's publisher lists in its own feed for Apple Podcasts (`ownerName`, `ownerEmail`), useful for guest booking and sponsorship outreach. Needs episodes on (the feed is read then). Turn off if you don't need personal contact data.

## Actor input object example

```json
{
  "searchTerms": [
    "true crime"
  ],
  "chartLimit": 25,
  "country": "us",
  "maxResultsPerSearch": 20,
  "includeEpisodes": true,
  "maxEpisodesPerPodcast": 10,
  "includeRating": false,
  "includeOwnerContact": true
}
```

# Actor output Schema

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

One item per podcast (type=podcast) and one per episode (type=episode).

# 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 = {
    "searchTerms": [
        "true crime"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tidyharvest/podcast-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 = { "searchTerms": ["true crime"] }

# Run the Actor and wait for it to finish
run = client.actor("tidyharvest/podcast-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 '{
  "searchTerms": [
    "true crime"
  ]
}' |
apify call tidyharvest/podcast-scraper --silent --output-dataset

```

## MCP server setup

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