# Podcast Scraper — Apple Podcasts, Episodes & Emails (`pixflor/apple-podcasts-scraper`) Actor

Scrape Apple Podcasts: shows, full episode lists, top charts by country and genre, plus owner names and contact emails pulled from each show's RSS feed. Gets past the 100-result search ceiling.

- **URL**: https://apify.com/pixflor/apple-podcasts-scraper.md
- **Developed by:** [Pixflor](https://apify.com/pixflor) (community)
- **Categories:** Lead generation, Social media, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 row 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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Podcast Scraper — Apple Podcasts, Episodes & Emails

Apple Podcasts as clean rows: shows with genres and activity signals, complete episode lists,
top charts by country and genre — and the one field Apple doesn't give you, **the owner's
contact email**.

No API key. No login. Type a topic, press start, export CSV or JSON.

***

### Three things this does that other podcast scrapers don't

#### 1. It gets the contact email — which isn't in Apple's API at all

Apple returns a `feedUrl` and nothing about who runs the show. The RSS feed at that URL carries
`<itunes:email>` and `<itunes:name>`.

Measured on a sample of startup podcasts: **7 of 7 exposed a contact address.**

That single field is the difference between a list of podcast names and a list you can
actually do something with — guest pitching, sponsorship outreach, PR. Turn on **Fetch owner
contact details** and every row gains `ownerName`, `ownerEmail`, `website`, `language` and the
feed's own episode count.

#### 2. It doesn't return the same 50 podcasts three times

Apple's search endpoint accepts an `offset` parameter, returns HTTP 200, and **ignores it
completely**. Measured: `offset=0`, `offset=50` and `offset=100` returned byte-identical
result sets.

A scraper that pages by offset reports 150 podcasts and delivers **50**, two thirds of them
duplicates, with nothing anywhere indicating a problem.

Search also silently caps at 100 — `limit=200` returns 100.

So how do you get more? **Storefronts.** Apple runs a separate catalogue per country, and they
genuinely differ:

| Storefronts searched | Unique podcasts for "technology" |
|---|---|
| US only | **100** — the hard ceiling |
| US + GB + CA + AU + IE | **226** |

This Actor partitions across storefronts and deduplicates the overlap for you.

#### 3. Episodes actually go deep

The 100 cap is on *search*, not on episodes. This Actor pulls up to 200 episodes per show,
with duration, publish date, audio URL, episode and season numbers.

One honest note: Apple omits duration on some episodes — measured 82.5% coverage on one show,
100% on another. Where it's missing, `durationMinutes` is `null` rather than a guess. That's
Apple's gap, and the row is still worth having.

***

### What you get

**Podcasts** — `name`, `artist`, `feedUrl`, `appleUrl`, `artworkUrl`, `primaryGenre`,
`genres`, `episodeCount`, `latestEpisodeAt`, **`daysSinceEpisode`**, **`isActive`**,
`explicit`, `contentRating`, `country`, `storefront`.

With contact enrichment on, add: `ownerName`, `ownerEmail`, `website`, `language`,
`copyright`, `summary`, `episodeCountInFeed`, `lastBuildDate`, `feedStatus`.

**Episodes** — `title`, `description`, `publishedAt`, `durationMinutes`, `audioUrl`,
`appleUrl`, `episodeNumber`, `seasonNumber`, `explicit`, `artworkUrl`.

**Chart entries** — `rank`, `country`, `name`, `artist`, `primaryGenre`, `appleUrl`.

Two small things done right: the useless `"Podcasts"` genre that every single show carries is
stripped out, so the genre field is actually filterable. And `lookup` returns the show
alongside its own episodes — this Actor filters that out, so a show is never counted as one of
its own episodes.

***

### Typical uses

- **Podcast outreach and PR.** Shows in your niche, active in the last 90 days, above an
  episode threshold, with a contact email. That's a pitch list.
- **Sponsorship prospecting.** Filter by genre and activity, then sort by episode count.
- **Booking guests / getting booked.** Find every show covering your topic across five English
  storefronts, not the first 100 in one.
- **Market research.** Chart positions by country and genre, tracked over time.
- **Content analysis.** Full episode histories with durations and publish cadence.
- **Feeding an LLM or agent.** One row per item, consistent field names, HTML stripped.

***

### Reliability

Apple's public iTunes Search API plus each show's own public RSS feed. No HTML scraping and no
bot-detection workarounds anywhere.

A 62-assertion live test suite runs before every release, including assertions that `offset` is
still ignored, that the 100 cap still bites, that storefront partitioning still beats it, and
that every extracted email is a valid address.

RSS feeds are third-party hosts, so some are slow or dead. Those rows come back with
`feedStatus` explaining why — `ok`, `unreachable` or `no_feed_url` — rather than failing the
run or handing you a blank field with no explanation.

***

### Pricing

Pay per event. You are charged for the run start and for each row returned — nothing else, and
platform compute is included free. Contact enrichment is opt-in because it costs an extra
request per show.

# Actor input Schema

## `mode` (type: `string`):

Pick one. 'search' finds podcasts by keyword. 'charts' returns the top podcasts for a country and genre. 'episodes' lists episodes for specific shows. 'lookup' fetches specific shows by ID.

## `searchTerm` (type: `string`):

What to search for, e.g. startup, true crime, marketing, history. Required for search mode.

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

Only used by the episodes and lookup modes. Accepts an iTunes ID (1434243584) or an Apple Podcasts URL.

## `countries` (type: `array`):

Apple runs a separate catalogue per country, and search returns at most 100 per query with no way to page. Adding storefronts is the only way past that ceiling: measured, one country gave 100 podcasts and five gave 226. Also controls which country's charts you get.

## `genre` (type: `string`):

Filter search results, or pick the chart genre.

## `includeContact` (type: `boolean`):

Reads each show's RSS feed to get the owner name and contact email, which the Apple API does not return at all. Measured 7 of 7 on a sample. This is the field that turns a podcast list into an outreach list. Costs one extra request per show.

## `episodesPerPodcast` (type: `integer`):

Only used by episodes mode. Unlike search, episodes really do go deep - 200 per show works.

## `minEpisodes` (type: `integer`):

Keep only shows with at least this many episodes. Useful for filtering out abandoned one-off shows.

## `activeOnly` (type: `boolean`):

Keep only podcasts that published in the last 90 days.

## `withEmailOnly` (type: `boolean`):

Drop shows with no contact address. Needs 'Fetch owner contact details' turned on, since the email is not in the Apple API.

## `excludeExplicit` (type: `boolean`):

Drop podcasts marked explicit.

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

Keep only shows whose RSS declares this language, e.g. en, de, es. Needs 'Fetch owner contact details' on, since language comes from the feed.

## `sortBy` (type: `string`):

How to order the results.

## `maxItems` (type: `integer`):

How many rows to return, and what you pay for.

## Actor input object example

```json
{
  "mode": "search",
  "searchTerm": "startup",
  "podcasts": [
    "1434243584"
  ],
  "countries": [
    "US",
    "GB",
    "CA",
    "AU",
    "IE"
  ],
  "genre": "all",
  "includeContact": false,
  "episodesPerPodcast": 20,
  "minEpisodes": 0,
  "activeOnly": false,
  "withEmailOnly": false,
  "excludeExplicit": false,
  "language": "en",
  "sortBy": "default",
  "maxItems": 100
}
```

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("pixflor/apple-podcasts-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("pixflor/apple-podcasts-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call pixflor/apple-podcasts-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=pixflor/apple-podcasts-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/wob9fQgH8Esy3eeaB/builds/qviiLV1rpLBZErXBG/openapi.json
