# 🎙️ Podcast Directory Scraper — Host Contacts & Emails (`citrine_venus/podcast-directory-scraper`) Actor

Turn Apple Podcasts searches, charts, or links into podcast host emails, websites, and social contacts. No API key needed. Get RSS-enriched leads with confidence-scored emails and an outreach lead score for podcast outreach and PR pitching.

- **URL**: https://apify.com/citrine\_venus/podcast-directory-scraper.md
- **Developed by:** [Data Minds](https://apify.com/citrine_venus) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $25.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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 Directory Scraper — Host Contacts & Emails

Turn any Apple Podcasts search, chart or link into a scored, enrichable list of **podcast host emails, websites and social contacts** — streamed straight to your Apify dataset.

🔗 **[View this Actor on Apify Store](https://apify.com/citrine_venus/podcast-directory-scraper)**

***

### 📑 Table of Contents

- [Introduction](#-introduction)
- [What data can you extract from Apple Podcasts?](#-what-data-can-you-extract-from-apple-podcasts)
- [How the podcast scraper works](#-how-the-podcast-scraper-works)
- [Input parameters reference](#-input-parameters-reference)
- [Output example](#-output-example)
- [FAQ](#-faq)
- [Support](#-support)

***

### 🎙 Introduction

#### 🎙 What is Podcast Directory Scraper?

**Podcast Directory Scraper** is an [Apify Actor](https://docs.apify.com/platform/actors) — a **podcast scraper** and **podcast host email finder** in one — that turns Apple Podcasts into a workable **podcast host contact database**. Point it at a keyword, a chart, or a list of show links, and it discovers matching shows, opens each one's **RSS feed** and website, and returns a clean dataset row per podcast. Each row carries the **host's email address**, owner name, social profiles, ratings, real publishing cadence, and a computed **outreach lead score**. It is built specifically for **podcast outreach leads**, not general podcast metadata — email quality and reachability are the whole point.

Unlike scraping the Apple Podcasts website by hand, this Actor talks to the same private **amp-api** the Apple Podcasts web app itself uses, backed by the public **iTunes Search/Lookup API** for feed URLs — no login, no API key, and no Apple Developer account required.

**Main features:**

- 🔎 **Bulk keyword search** — one topic or a hundred, each searched separately and merged.
- 🎧 **Episode-level keyword search** — finds shows that *talked about* your topic even when the show title never mentions it.
- 🔗 **Bulk direct input** — Apple Podcasts links, bare show IDs, or RSS feed URLs, mixed freely.
- 🏆 **Top-chart harvesting** — sweep a category's rankings with chart position preserved.
- 📧 **Typed, confidence-scored email extraction** — every address comes with a source, a type, and a 0–100 confidence score, not just a yes/no.
- 🌐 **Website contact fallback** — checks the show's homepage and contact/about pages when the RSS feed has no address.
- 📅 **Real publishing cadence** — computed from the actual gaps between episode dates, not the show's self-reported frequency.
- 🎯 **0–100 outreach lead score** — ranks shows by how reachable and how active they actually are.
- 💸 **Quality filters that cut cost** — filtered-out shows are never saved and never billed.

Running this on Apify also means you get the platform's built-in advantages for free: **scheduling** recurring refreshes of a niche, **monitoring** and email alerts if a run's yield drops, instant **API and webhook access** to every dataset, and automatic **proxy rotation** if Apple's directory ever pushes back — none of which you get running a local script.

#### 📊 What data can you extract from Apple Podcasts?

In plain terms, every row this **podcast scraper** returns groups into six kinds of information:

- 🏷️ **Who the show is** — title, host/author name, description, categories, language, artwork, and country of origin.
- 📧 **How to reach them** — host email (typed and confidence-scored), owner name, website, social profiles (X/Twitter, LinkedIn, Instagram, YouTube, Facebook, TikTok), and a funding/support link.
- 📈 **How active they are** — first and last episode dates, days since the last episode, real publishing frequency, and whether the show has ended.
- ⭐ **How big the audience is** — star rating, rating count, the full star-by-star breakdown, and a popularity tier.
- 🎯 **How good a lead it is** — a 0–100 outreach lead score, a reachability verdict, and a data-quality flag.
- 🔗 **Where it came from** — the RSS feed URL, the Apple Podcasts link, which keyword or chart matched, and when the row was collected.

The full technical field list, with exact names and types, is in the [output example](#-output-example) below.

***

### 🔧 How the podcast scraper works

1. **You choose a discovery mode.** Keyword search matches show titles and authors; episode keyword search matches what was actually said inside episodes; top charts pulls a category's rankings; direct links/IDs/RSS scrapes exactly the shows you paste.
2. **The Actor queries Apple's own amp-api and the public iTunes API**, merging and deduplicating results by show ID.
3. **Each show's profile is filled in** — ratings, categories, episode counts, artwork, ended-show flag — from batched Apple lookups.
4. **The show's RSS feed is opened** to pull the host email, owner name, real website, credited hosts, funding link, and the full episode list — this is where nearly all contact data comes from.
5. **If the feed has no usable address**, the show's own website (homepage plus contact/about pages) is checked as a fallback.
6. **Every candidate email is scored and typed**, the best one becomes `ownerEmail`, and up to three runners-up are kept as `alternateEmails`.
7. **Cadence is computed** from the real gaps between episode dates, and a 0–100 lead score is calculated from reachability, activity, cadence and audience size.
8. **Your quality filters are applied**, and every show that passes is pushed to your dataset immediately — nothing waits for the run to finish.

***

### 📋 Input parameters reference

#### 🚀 Start here — what to find

| Parameter | Type | Description | Default |
|---|---|---|---|
| `searchTerms` | array | Topics, niches or show names to search — for example `b2b saas marketing`, `true crime`. One keyword per line, bulk supported. | `[]` |
| `urls` | array | Apple Podcasts links, bare show IDs, or direct RSS feed URLs to scrape exact shows. Bulk paste or file upload. | `[]` |
| `podcastIds` | array | Bare Apple Podcasts show IDs, one per line. Processed together with `urls`. | `[]` |
| `maxResultsPerTerm` | integer | How many shows to collect per keyword. | `50` (prefill `25`) |
| `country` | string | Which Apple Podcasts store to search (two-letter code, 175 supported). | `"us"` |

#### 🎯 How to discover shows

| Parameter | Type | Description | Default |
|---|---|---|---|
| `mode` | string | Discovery mode: `search` (title/author match), `episodes` (episode-level topic search), `charts` (top-charts harvest), `ids` (direct links/IDs/RSS only). | `"search"` |
| `episodeSearchTerms` | array | Phrases to look for inside episode titles and notes, used only in `episodes` mode. Falls back to `searchTerms` if left empty. | `[]` |
| `chart` | string | Which chart to use in `charts` mode: `top-series`, `top`, `top-subscriber`. | `"top-series"` |
| `chartGenres` | array | Category names to sweep in `charts` mode. Empty sweeps every top-level category. | `[]` |
| `maxPodcasts` | integer | Hard cap on total podcasts saved across the whole run. `0` = no limit. | `0` |

#### 📧 Contact enrichment

| Parameter | Type | Description | Default |
|---|---|---|---|
| `fetchRss` | boolean | Read each show's RSS feed for host email, owner name, website, cadence and episodes. | `true` |
| `scrapeWebsite` | boolean | Check the show's own website when the feed has no email. | `true` |
| `websiteMaxPages` | integer | Extra contact/about pages to check beyond the homepage. | `2` |
| `includeSocialLinks` | boolean | Collect X/Twitter, LinkedIn, Instagram, YouTube, Facebook and TikTok profiles. | `true` |

#### 🎧 Output options

| Parameter | Type | Description | Default |
|---|---|---|---|
| `includeEpisodes` | boolean | Add recent episode listings (title, notes, date, duration, audio URL, guests) to every row. | `false` |
| `maxEpisodesPerShow` | integer | Episodes to include per show. `0` = every episode in the feed. Cadence is always computed from the full feed regardless of this cap. | `10` |
| `includeRatingHistogram` | boolean | Add the 1★–5★ vote-count breakdown. | `false` |

#### 🎛️ Quality filters

Filtered shows are never saved — and never charged.

| Parameter | Type | Description | Default |
|---|---|---|---|
| `activeOnly` | boolean | Keep only shows with an episode in the last 90 days. | `false` |
| `activeWithinDays` | integer | Custom activity window in days; overrides `activeOnly`. `0` disables it. | `0` |
| `excludeCompleted` | boolean | Drop shows Apple flags as completed/ended. | `false` |
| `requireEmail` | boolean | Keep only shows with a usable host email. | `false` |
| `requireWebsite` | boolean | Keep only shows with their own website. | `false` |
| `excludeExplicit` | boolean | Drop shows marked explicit. | `false` |
| `minLeadScore` | integer | Minimum 0–100 lead score to keep. | `0` |
| `minEpisodes` | integer | Minimum episode count. | `0` |
| `minRatingCount` | integer | Minimum number of listener ratings. | `0` |
| `minRating` | number | Minimum star rating (0–5). A minimum rating count of 1 is applied automatically. | `0` |
| `emailTypes` | array | Keep only these email types: `role`, `personal`, `generic`, `platform`. | `[]` |
| `frequencies` | array | Keep only these cadences: `daily`, `multiple-per-week`, `weekly`, `biweekly`, `monthly`, `irregular`, `infrequent`. | `[]` |
| `languages` | array | Keep only these two-letter language codes. | `[]` |
| `categoryFilter` | array | Keep only categories matching these keywords (partial match). | `[]` |

#### 🌍 Network

| Parameter | Type | Description | Default |
|---|---|---|---|
| `proxyConfiguration` | object | Proxy route override. By default the run starts direct and escalates automatically to datacenter, then residential, if the directory pushes back. | `{"useApifyProxy": false}` |

#### ⚡ Speed & limits

| Parameter | Type | Description | Default |
|---|---|---|---|
| `concurrency` | integer | Podcasts processed in parallel. | `8` |
| `requestDelaySeconds` | number | Pause between requests, in seconds. | `0` |
| `maxRetries` | integer | Retries per request before escalating the network route. | `3` |
| `maxScanned` | integer | Safety valve: stop after examining this many shows, even if filters rejected all of them. `0` = no limit. | `20000` |
| `maxRunSeconds` | integer | Stop cleanly after this many seconds, keeping everything already saved. `0` = no limit. | `0` |

***

### 📦 Output example

Each podcast this scraper finds is pushed to the dataset as one JSON object, in this shape:

```json
{
  "podcastId": "1496516404",
  "title": "Breaking B2B - SaaS Marketing and B2B Marketing Podcast",
  "author": "Sam Dunning",
  "description": "Break free from sh*t SaaS and b2b marketing. Join 1000s of legends tuning in weekly.",
  "categories": ["Business", "Marketing", "Entrepreneurship", "Careers"],
  "language": "en",
  "storefront": "us",
  "countryOfOrigin": "USA",
  "episodeCount": 499,
  "seasonCount": null,
  "firstPublishedDate": "2020-01-25",
  "lastEpisodeDate": "2026-08-27",
  "daysSinceLastEpisode": 2,
  "episodeFrequency": "weekly",
  "medianGapDays": 4.1,
  "appleReleaseFrequency": "Updated Biweekly",
  "isActive": true,
  "isCompleted": false,
  "showType": "episodic",
  "mediaKinds": ["audio"],
  "contentRating": "clean",
  "accessType": "free",
  "hasPaidSubscription": false,
  "ratingAverage": 4.8,
  "ratingCount": 23,
  "ratingHistogram": [0, 1, 0, 2, 20],
  "popularityTier": "low",
  "applePodcastsUrl": "https://podcasts.apple.com/us/podcast/breaking-b2b/id1496516404",
  "feedUrl": "https://feeds.simplecast.com/WtYkR7bN",
  "feedGuid": null,
  "feedError": null,
  "websiteUrl": "https://www.breakingb2b.com/blog",
  "artworkUrl": "https://is1-ssl.mzstatic.com/image/thumb/…/600x600bb.jpg",
  "ownerName": "Sam Dunning",
  "ownerEmail": "samuelmdunning@gmail.com",
  "emailSource": "rss_owner",
  "emailType": "personal",
  "emailScore": 65,
  "alternateEmails": null,
  "people": null,
  "socialLinks": {
    "linkedin": "https://linkedin.com/in/samdunning",
    "youtube": "https://youtube.com/channel/UC7OhjYB9-p0b6ZNnXMOzjLQ"
  },
  "fundingUrl": null,
  "isLockedFeed": false,
  "leadScore": 83,
  "dataQuality": "high",
  "hasEmail": true,
  "hasWebsite": true,
  "hasSocial": true,
  "contactability": "probable",
  "source": "apple",
  "discoveryMode": "search",
  "searchTerm": "b2b saas marketing",
  "chartRank": null,
  "matchedEpisodes": null,
  "episodes": [
    {
      "title": "#498 Copy This AI SEO Strategy, It Will Blow Up Your SaaS",
      "description": "This week, Sam gives you the exact 3-page AI SEO framework…",
      "publishDate": "2026-08-27",
      "duration": "00:24:11",
      "audioUrl": "https://cdn.simplecast.com/audio/…/episode.mp3",
      "episodeNumber": 498,
      "seasonNumber": null,
      "guid": "b0f4e2c1-…",
      "transcriptUrl": null,
      "guests": null
    }
  ],
  "scrapedAt": "2026-08-29T10:12:44+00:00"
}
```

#### 🔍 Fields worth explaining

| Field | Meaning |
|---|---|
| `emailSource` | Exactly where the address was found: `rss_owner`, `rss_googleplay`, `rss_locked`, `rss_editor`, `rss_webmaster`, `rss_description`, `website_contact`, or `website_home`. Feed-published addresses always outrank scraped ones. |
| `emailType` | `role` (booking@, press@, hello@), `personal` (a named human), `generic` (support@, admin@), or `platform` (a hosting provider's shared inbox, scored down hard). |
| `emailScore` | 0–100 **email confidence score** — how likely this address is to be the show's real, checked inbox, based on where it was found and its shape. |
| `alternateEmails` | Up to three runner-up addresses, in case the best one bounces. |
| `contactability` | Plain-English reachability verdict: `direct`, `probable`, `weak`, `website-only`, or `none`. |
| `leadScore` | 0–100 **outreach lead score** — weighted toward a real inbox, an active show, a healthy cadence and a real audience; ended shows and hosting-platform inboxes are penalised. |
| `dataQuality` | `high` / `medium` / `low`, based on whether both an email and a website were found. |
| `medianGapDays` | The **median** number of days between episodes — used instead of the average so one long hiatus doesn't misclassify a weekly show as infrequent. |
| `appleReleaseFrequency` | What Apple's own directory claims the cadence is, kept alongside the computed `episodeFrequency` for comparison. |
| `source` | Always `"apple"` — the discovery API that produced the row. |
| `discoveryMode` | Which mode found this show: `search`, `episodes`, `charts`, or `ids`. |
| `matchedEpisodes` | In episode-keyword-search mode, the specific episodes that matched your topic. |

***

### ❓ FAQ

#### ⚖️ Is it legal to scrape Apple Podcasts and podcast RSS feeds?

Yes, within normal limits. This Actor reads **publicly available** Apple Podcasts listings and **publicly published RSS feeds** — the same data any podcast app or listener can access without logging in. RSS feeds exist specifically to be read by software. You are still responsible for how you use any personal data (a host's name or email) — follow GDPR, CCPA and CAN-SPAM/CASL rules if you use the data for outreach. See Apify's [guide on the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/) for background. This isn't legal advice.

#### 🔍 How is this different from just searching Apple Podcasts manually?

Manually searching Apple Podcasts gets you a title, artwork and a description — no host email, no real publishing cadence, and no way to search inside episode content. This Actor opens every show's RSS feed and website for you, extracts and types the actual host email with a confidence score, computes real cadence from episode dates instead of trusting Apple's own label, and supports **episode-level keyword search** — finding shows that discussed your topic even when it never appears in the title, which manual search on Apple Podcasts simply cannot do.

#### 🎤 How do I find podcasts looking for guests?

Run a keyword search for your topic or niche, turn on `requireEmail`, and sort the results by `leadScore`. High-scoring, currently active shows with a direct or probable contact channel are your best guest-pitch candidates — most independent podcasts are actively looking for guests even if they don't say so explicitly.

#### 📧 How do I find a podcast host's contact email address?

Point the Actor at the show (by keyword, chart, or a direct Apple Podcasts link/RSS feed URL) with `fetchRss` and `scrapeWebsite` both on. It reads the RSS feed's owner tag first — the address creators publish specifically for this purpose — and falls back to the show's contact or about page if the feed carries none. The result lands in `ownerEmail`, already typed and scored.

#### 🎯 How do I pitch a podcast for a guest appearance?

Start from a lead list, not a cold search: filter for `emailType` of `role` or `personal` (skip `platform` inboxes, which are shared hosting addresses), a `contactability` of `direct` or `probable`, and an active `episodeFrequency`. Pitch shows that are still publishing regularly — a show with `isCompleted: true` or no episode in 180+ days is unlikely to book anyone.

#### 🔌 Does this use the official Apple Podcasts API or the iTunes API?

Neither is a public, documented "Apple Podcasts API" in the traditional sense. This Actor combines two real Apple endpoints: the private **amp-api** that powers the Apple Podcasts web app itself, and the public **iTunes Search/Lookup API**, mainly for resolving each show's RSS `feedUrl`. No login or API key is required for either.

#### 🛡️ Why doesn't this scraper break when Apple changes something?

Most Apple Podcasts scrapers hardcode an API token and endpoint list that Apple periodically rotates, which is why they silently stop working. This Actor is **self-healing**: at the start of every run it fetches Apple's own current web-app JavaScript bundle and extracts the live amp-api token, hosts and endpoint contract straight out of it — the same values the real Apple Podcasts website is using that day — rather than trusting a value baked in months earlier.

#### 📭 Why does a show have no email address?

Not every podcast publishes one. Hobbyist and personal shows omit a contact address far more often than professionally produced business, marketing, technology and health shows. Turn on `requireEmail` so you're never billed for a show you can't actually reach.

#### 🌍 Can I search several countries or use it as a podcast RSS feed API?

Each run searches one Apple Podcasts store, since charts and rankings are country-specific — run it again with a different `country` code, or schedule separate tasks. You can also skip discovery entirely and feed it RSS feed URLs directly through the `urls` field to use it purely as a **podcast RSS feed API** for enrichment.

#### 💰 How much does it cost to scrape podcast data with this Actor?

This Actor runs on Apify's **pay-per-event** pricing, billed per `podcast-scraped` event — one charge for each podcast row actually saved to your dataset, after your quality filters run. Shows removed by filters like `requireEmail` and `minLeadScore` are never saved and never billed, so you only pay for qualified **podcast outreach leads**, not raw listings.

#### 🤖 Can I use the results with an AI agent or automation pipeline?

Yes. As a pay-per-event Actor it's callable as a single tool step from Make, Zapier, n8n, or any MCP-compatible AI agent — "find active B2B podcasts with a booking email and 100+ ratings" becomes one Actor call, and results are available immediately via the [Apify API](https://docs.apify.com/api/v2) in JSON, CSV, Excel or XML.

***

### 💬 Support

Found a bug, need a field this Actor doesn't expose, or want a custom outreach pipeline built around it? Open an issue on the Actor's **Issues** tab in Apify Console, or reach out directly at **<hello.dataminds@gmail.com>**. If this Actor saved you time, a review on the Store page helps other users find it.

# Actor input Schema

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

🎯 Topics, niches or show names — for example `b2b saas marketing`, `true crime`, `health and fitness`, `startup founders`. Each keyword is searched on its own. Bulk input supported — paste one per line.

## `urls` (type: `array`):

📎 Scrape exact shows instead of (or on top of) a keyword search. Accepts <b>Apple Podcasts links</b> (`https://podcasts.apple.com/us/podcast/.../id1322200189`), <b>bare show IDs</b> (`1322200189`) and <b>direct RSS feed URLs</b> (`https://feeds.simplecast.com/qm_9xx0g`). Bulk input supported — one per line, or upload a file.

## `podcastIds` (type: `array`):

🔢 Bare Apple Podcasts show IDs, one per line — for example `1322200189`. Use this when you have plain IDs rather than full links; the URL field above only accepts real URLs. Both fields are processed together.

## `maxResultsPerTerm` (type: `integer`):

🎁 How many shows to collect for each keyword. Start with 10–25 for a quick sample, raise it for a full harvest.

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

🗺️ Which country's Apple Podcasts store to search. Charts and rankings are country-specific, so this changes what you get. Pick one or type any two-letter code — 175 stores are supported.

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

🔀 <b>Keyword search</b> matches show titles and authors. <b>Episode keyword search</b> finds shows that actually <i>talked about</i> your topic, even when their title never mentions it. <b>Top charts</b> harvests the store's own rankings. <b>Direct links</b> uses only the URLs/IDs you pasted above.

## `episodeSearchTerms` (type: `array`):

🗣️ Used only by <b>Episode keyword search</b>. Phrases to look for inside episode titles and notes — `series B funding`, `cold outreach`, `menopause`. Leave empty to reuse your main search keywords.

## `chart` (type: `string`):

📈 Used only by <b>Top charts</b> mode. `top-series` is the classic most-popular-shows chart.

## `chartGenres` (type: `array`):

🎨 Used only by <b>Top charts</b> mode. Category names such as `business`, `comedy`, `true crime`, `health & fitness`. Leave empty to sweep every top-level category.

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

🛑 Hard stop for the whole run, across every keyword and category. `0` means no limit. You are only charged for podcasts actually saved.

## `fetchRss` (type: `boolean`):

📬 Opens the show's own feed to pull the <b>host email</b>, owner name, real website, credited hosts, publishing cadence, funding link and episode list. Turn off for a fast metadata-only run.

## `scrapeWebsite` (type: `boolean`):

🔍 Falls back to the podcast's own website — homepage plus contact/about pages — to recover an address the feed did not publish. Measurably lifts email coverage.

## `websiteMaxPages` (type: `integer`):

🗂️ How many contact/about pages to open beyond the homepage. Higher finds more addresses but takes longer.

## `includeSocialLinks` (type: `boolean`):

📱 Twitter/X, LinkedIn, Instagram, YouTube, Facebook and TikTok profiles belonging to the show (guest and sponsor links are filtered out).

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

📻 Adds recent episodes per show — title, description, publish date, duration, audio URL, episode/season number, transcript link and credited guests. Turn off for smaller, faster rows.

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

📦 How many recent episodes to include per show. `0` returns every episode in the feed (can be very large). Publishing cadence is always calculated from the full feed regardless of this cap.

## `includeRatingHistogram` (type: `boolean`):

⭐ Adds the 1★–5★ vote counts alongside the average rating.

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

📅 Keep only shows that published an episode in the last 90 days. Shows whose feed could not be read are dropped too, since activity cannot be confirmed.

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

⏳ Keep only shows with an episode in the last N days. Overrides the 90-day switch above. `0` disables it.

## `excludeCompleted` (type: `boolean`):

🎬 Drop shows the store flags as completed/ended — they will never book a guest.

## `requireEmail` (type: `boolean`):

💰 Skip any show with no usable contact address. Filtered shows are never saved and never charged, so you only pay for contactable leads.

## `requireWebsite` (type: `boolean`):

🔗 Skip shows that publish no website of their own.

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

🧹 Drop shows marked explicit — useful for brand-safe sponsorship lists.

## `minLeadScore` (type: `integer`):

🎯 Skip shows scoring below this (0–100). Roughly: <b>60</b> keeps shows with at least one direct contact channel, <b>80</b> keeps active, well-rated shows with a real inbox. `0` keeps everything.

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

📚 Drop shows with fewer episodes than this — a quick way to filter out abandoned pilots.

## `minRatingCount` (type: `integer`):

📈 Drop shows with fewer listener ratings than this — a proxy for real audience size.

## `minRating` (type: `number`):

🌟 Drop shows rated below this on the 0–5 scale. A minimum rating count of 1 is applied automatically, because a 5.0 from zero raters is not a 5.0.

## `emailTypes` (type: `array`):

📮 <b>role</b> = booking@/press@/hello@ · <b>personal</b> = a named human · <b>generic</b> = support@/admin@ · <b>platform</b> = a podcast host's own inbox. Leave empty to keep every type.

## `frequencies` (type: `array`):

⏱️ Calculated from the real gaps between episodes, not from what the show claims. Leave empty to keep every cadence.

## `languages` (type: `array`):

🌐 Two-letter codes such as `en`, `es`, `de`. `en` also matches `en-US` and `en-GB`. Leave empty for every language.

## `categoryFilter` (type: `array`):

🎨 Partial matches count — `business` keeps `Business` and `Business News`. Leave empty for every category.

## `proxyConfiguration` (type: `object`):

🚦 By default the run starts on a <b>direct connection</b> and automatically switches to a <b>datacenter</b> and then a <b>residential</b> route only if the podcast directory pushes back. Once it switches it stays there for the rest of the run, and every change is logged. Pick your own route here to override that.

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

🏎️ How many show feeds and websites to open at the same time.

## `requestDelaySeconds` (type: `number`):

⏸️ Seconds to wait between requests. `0` is fine for normal runs; raise it if you are sweeping very large keyword sets.

## `maxRetries` (type: `integer`):

🔁 Attempts before the run escalates to the next network route.

## `maxScanned` (type: `integer`):

🧭 Safety valve: stop after checking this many shows, even if your filters rejected all of them. `0` means no limit.

## `maxRunSeconds` (type: `integer`):

⌛ Stop cleanly after this many seconds, keeping everything already saved. `0` means no time limit.

## Actor input object example

```json
{
  "searchTerms": [
    "b2b saas marketing"
  ],
  "urls": [],
  "podcastIds": [],
  "maxResultsPerTerm": 25,
  "country": "us",
  "mode": "search",
  "episodeSearchTerms": [],
  "chart": "top-series",
  "chartGenres": [],
  "maxPodcasts": 0,
  "fetchRss": true,
  "scrapeWebsite": true,
  "websiteMaxPages": 2,
  "includeSocialLinks": true,
  "includeEpisodes": false,
  "maxEpisodesPerShow": 10,
  "includeRatingHistogram": false,
  "activeOnly": false,
  "activeWithinDays": 0,
  "excludeCompleted": false,
  "requireEmail": false,
  "requireWebsite": false,
  "excludeExplicit": false,
  "minLeadScore": 0,
  "minEpisodes": 0,
  "minRatingCount": 0,
  "minRating": 0,
  "emailTypes": [],
  "frequencies": [],
  "languages": [],
  "categoryFilter": [],
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "concurrency": 8,
  "requestDelaySeconds": 0,
  "maxRetries": 3,
  "maxScanned": 20000,
  "maxRunSeconds": 0
}
```

# Actor output Schema

## `podcasts` (type: `string`):

Every podcast collected in this run, with all fields.

## `contacts` (type: `string`):

Contact-focused columns only — best for feeding an outreach tool.

## `leads` (type: `string`):

Lead score, reachability and data-quality grade per show.

## `csv` (type: `string`):

The same rows as a spreadsheet-ready CSV download.

## `runSummary` (type: `string`):

Totals, coverage percentages, email sources and filter rejections 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 = {
    "searchTerms": [
        "b2b saas marketing"
    ],
    "maxResultsPerTerm": 25,
    "country": "us",
    "mode": "search",
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("citrine_venus/podcast-directory-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": ["b2b saas marketing"],
    "maxResultsPerTerm": 25,
    "country": "us",
    "mode": "search",
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("citrine_venus/podcast-directory-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": [
    "b2b saas marketing"
  ],
  "maxResultsPerTerm": 25,
  "country": "us",
  "mode": "search",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call citrine_venus/podcast-directory-scraper --silent --output-dataset

```

## MCP server setup

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