Podcast Transcripts Scraper
Pricing
from $2.88 / 1,000 transcribed audio minutes
Podcast Transcripts Scraper
Discover new episodes from public podcast RSS feeds and export searchable transcripts, timestamped segments and SRT/VTT subtitles with bounded local speech recognition.
Pricing
from $2.88 / 1,000 transcribed audio minutes
Rating
0.0
(0)
Developer
Automation Lab
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
22 days ago
Last modified
Categories
Share
Turn the newest episodes in public RSS feeds into searchable podcast transcripts. Supply the feeds once instead of enumerating audio URLs: receive episode metadata, plain text, timestamped segments, and optional SRT/VTT subtitle files.
Built for researchers indexing recurring shows, editorial teams searching interviews, and knowledge pipelines collecting newly published speech. Recognition runs locally on CPU using Whisper tiny; no transcription API key is required.
What it does
- Downloads public RSS 2.0 feeds with audio enclosures.
- Applies an optional publication cutoff and previously indexed GUID exclusions.
- Selects the newest eligible episodes, deduplicating GUIDs and audio URLs.
- Downloads bounded audio, checks duration, and transcribes without clipping.
- Saves one episode record and optional subtitle artifacts in run storage.
This is not a podcast search engine. It does not resolve Apple Podcasts or Spotify landing pages, authenticate to private feeds, or fetch an entire historical archive.
Who is it for?
Research teams building a public-interview corpus, editors reviewing recent show episodes, and data engineers maintaining searchable episode indexes. It is not suitable for confidential recordings or a verbatim legal transcript.
Why use it?
A direct-media transcriber needs individual file URLs. This Actor discovers those URLs from your feeds and preserves the episode identity alongside each transcript. Date and GUID filters make recurring indexing explicit and reproducible without hidden cross-run state.
Outputs are machine-readable and can be joined to your own episode index. Speech recognition is approximate: manually verify quotations, names, numbers, and consequential interpretations.
Getting started
- Copy the public RSS feed URL from the show's publisher.
- Start with one episode and a duration bound suitable for the show.
- Run the Actor and open Episode transcripts in the output tab.
- Download subtitles from the links in
subtitleUrls. - Save successful GUIDs externally for the next indexing run.
{"feedUrls": ["https://feeds.npr.org/500005/podcast.xml"],"maxItems": 1,"episodesPerFeed": 1,"maxDurationMinutes": 10,"language": "en","outputFormats": ["srt", "vtt"]}
The example uses a public, frequently updated short news feed; episode identity changes over time.
Inputs
| Field | Default | Behavior |
|---|---|---|
feedUrls | Required | 1–5 public RSS 2.0 URLs; strings, no credentials or query strings |
maxItems | 1 | Global selected episode cap, 1–10 |
episodesPerFeed | 1 | Eligible newest episodes selected per feed, 1–10 |
publishedAfter | Unset | Strictly later than a UTC ISO timestamp ending in Z |
excludeGuids | [] | Exact, case-sensitive GUID exclusions, up to 1000 |
maxFileSizeMb | 50 | Hard per-audio bound, 1–100 MiB |
maxDurationMinutes | 10 | Hard per-episode duration bound, 1–30 minutes |
language | auto | Automatic detection or a supported two-letter Whisper code |
outputFormats | ["srt","vtt"] | Either/both formats; [] disables artifacts |
Feed downloads are capped at 2 MiB. Only audio/* enclosures are selected. Missing GUIDs use the enclosure URL. Duplicate feeds are removed.
Selection and recurring indexing
Filters apply before per-feed limits. Entries are newest-first by RSS publication date; undated entries follow dated entries in feed order. With publishedAfter, undated entries are excluded. The cutoff is strictly greater than, not equal to, the supplied timestamp.
Per-feed selections are combined, deduplicated by GUID and enclosure URL, sorted newest-first across all feeds, then capped by maxItems. Failed episodes consume a selected slot; the Actor does not silently substitute older episodes. GUID collisions across shows are deduplicated too.
The Actor saves no cross-run cursor. Store successful GUIDs and a publication watermark in your own database. On the next run pass them back as exclusions/cutoff. Feeds may remove old entries; increasing limits does not recover an archive. There are no built-in change alerts.
Output data
| Field | Meaning |
|---|---|
feedUrl, showTitle | Feed identity and RSS channel title |
guid, episodeTitle, episodeUrl | Episode identity, title and optional page link |
publishedAt, audioUrl | ISO publication date (nullable) and public audio enclosure URL |
status | succeeded or failed |
transcript | Recognized plain text; null on failure |
segments | {id,start,end,text} records; times in seconds |
language, languageProbability | Recognition language and confidence; null on failure |
durationSeconds, model | Decoded duration and tiny model |
subtitleUrls | Requested format download links; empty when disabled/failed |
processedAt, error | Processing timestamp and safe error explanation |
A successful local NPR episode produced the opening text “This is NPR News Now. The latest headlines every hour.”, with segment 0 covering 0–4.44 seconds. Later recognition included errors in names, illustrating why tiny-model output needs review. Dataset records contain the full episode transcript rather than just this excerpt.
{"showTitle": "NPR News Now","status": "succeeded","model": "tiny","language": "en","segments": [{"id": 0, "start": 0, "end": 4.44, "text": "This is NPR News Now."}]}
This is an excerpt, not a complete output record. Dataset exports support JSON, CSV and other Apify formats. Keep nested segments in JSON when you need timestamps.
Subtitle artifacts
SRT and VTT files use the recognized segment timing. Keys follow EPISODE_001.SRT and EPISODE_001.VTT; links are returned in each successful record. Files live in the run's default key-value store. Download before your storage retention period expires. There is no separate subtitle event charge.
How much does it cost to transcribe podcast episodes?
Pay-per-event pricing consists of a $0.005 start fee, charged once for the first successfully recognized episode, plus rounded-up decoded audio minutes. Each episode rounds separately; 61 seconds counts as two minutes. Download/recognition failures, silent audio and oversized episodes have no audio-minute charge. Required charges are verified before transcript or subtitle output is exposed. A billing or subsequent storage failure is fatal; a storage failure can leave charges for recognized audio without a complete dataset row. Inspect the failed run before retrying.
BRONZE price: $0.0048 per audio minute. A five-minute episode costs approximately $0.029 including the start event; ten minutes costs $0.053. Each episode rounds independently.
| Spend tier | Price per audio minute |
|---|---|
| FREE | $0.00552 |
| BRONZE | $0.0048 |
| SILVER | $0.003744 |
| GOLD | $0.00288 |
| PLATINUM | $0.00288 |
| DIAMOND | $0.00288 |
Spend tiers reflect qualifying aggregate monthly Apify Store spend, not private per-Actor volume discounts. Prices are estimates, not a guaranteed invoice; the applicable live tier and maximum-charge budget govern the run. Storage/platform terms also apply. Refunds, disputes, fraud, taxes, corrections, and contractual clawbacks can affect finalized revenue or payouts.
A maximum-charge budget can stop output before ASR for the next complete episode if its combined start (when needed) and full minute charge cannot be covered; the final log explicitly says budget-limited and any returned dataset is partial. Avoid setting a budget too small for the requested duration.
Limits and failure behavior
Audio is processed sequentially in bounded 60-second recognition chunks with episode-wide timestamps. A chunk boundary can split a phrase; the text remains approximate. Automatic language detection uses the first chunk with recognized speech and reuses that language for the episode. Downloads are bounded by bytes and a two-minute deadline across redirects. Recognition has a per-file timeout. There is no proxy or browser fallback and no automatic retry loop; retry a transient source failure in a new authorized run.
Over-duration or unknown-duration files fail, rather than returning a silently clipped transcript. Bad feeds fail discovery. Episode failures create uncharged error records and mark the run FAILED after preserving any successful transcripts. Billing or output-storage errors are fatal. A failed run can contain useful partial results: inspect status, never assume full completion.
Integrations
- Research index: upsert successful records keyed by feed URL plus GUID; index transcript text and retain segments for playback citations.
- Editorial workflow: export JSON to a review queue, download SRT/VTT, and manually correct quotations.
- Scheduled collection: use Apify schedules with your own watermark/GUID state. Schedules do not automatically update input state.
- Data pipelines: use a completion webhook to fetch the dataset and send it to your warehouse or search engine. Handle failed runs as partial.
API usage
Start a run asynchronously and keep the returned run ID:
curl -X POST 'https://api.apify.com/v2/acts/automation-lab~podcast-feed-episode-transcripts/runs' \-H "Authorization: Bearer $APIFY_TOKEN" -H 'Content-Type: application/json' \-d '{"feedUrls":["https://feeds.npr.org/500005/podcast.xml"],"maxItems":1}'
JavaScript with the Apify client:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('automation-lab/podcast-feed-episode-transcripts').call({ feedUrls: ['https://feeds.npr.org/500005/podcast.xml'], maxItems: 1 });const result = await client.dataset(run.defaultDatasetId).listItems({ limit: 10 });console.log(run.status, result.items);
Python:
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ['APIFY_TOKEN'])run = client.actor('automation-lab/podcast-feed-episode-transcripts').call(run_input={'feedUrls': ['https://feeds.npr.org/500005/podcast.xml'], 'maxItems': 1})rows = client.dataset(run['defaultDatasetId']).list_items(limit=10).itemsprint(run['status'], rows)
MCP usage
Select this stable Actor subset:
claude mcp add --transport http apify \"https://mcp.apify.com?tools=automation-lab/podcast-feed-episode-transcripts"
Equivalent Claude Desktop, Cursor, and VS Code setup configuration (use each client's supported HTTP MCP configuration):
{"mcpServers":{"apify":{"url":"https://mcp.apify.com?tools=automation-lab/podcast-feed-episode-transcripts"}}}
Discover actual names and argument schemas with scoped tools/list. Actor selection also includes get-actor-run, get-dataset-items, get-key-value-store-record, and abort-actor-run; discovery alone does not authorize a run or abort.
Example prompt: “Transcribe the newest episode from this public RSS feed, then give me the transcript and subtitle links. Show any recognition uncertainty.”
For an authorized invocation, start once and retain the run/storage IDs; they are metadata, not results. call-actor waits at most 45 seconds (default 30). If nonterminal, check the same run with 2/4/8-second backoff capped at 10 seconds and a 120-second consumer deadline. Client timeout should exceed server wait plus transport margin. On timeout recover the known run, never restart merely to poll. At the deadline report pending with its ID.
Report terminal failures honestly: any available rows are partial, not a successful full result. Once successful, call the discovered get-dataset-items helper with explicit limit, offset, and fields (a comma-separated string). For example:
{"datasetId":"<defaultDatasetId from the same run>","limit":20,"offset":0,"fields":"guid,showTitle,episodeTitle,publishedAt,status,transcript,subtitleUrls,error"}
Request segments only when timestamps are needed. Fetch pages of 20 source rows from offset 0, at most 100 rows and 64 KiB of serialized UTF-8 data admitted to model context, whichever comes first. Process pages host-side; omit/summarize an oversized row with disclosure. If your client cannot intercept oversized responses, do not claim a hard byte ceiling. Track source offsets; report partial/truncated status and continuation offset. Keep full transcripts in storage outside model context when needed. Discovery transport and caching do not guarantee token savings.
AI and data handling
Whisper tiny via faster-whisper/CT2 runs on the Actor's CPU, with int8 inference. No media or transcript is sent to an external transcription/LLM provider, no model training occurs, and no diarization, translation or professional-grade accuracy is promised. Model weights are fetched during image construction, not from customer audio. Different languages, accents, music, crosstalk and noise can reduce accuracy.
Feed metadata, public audio URLs, recognized speech and subtitles are stored in your Apify run storage. Audio/WAV working files are deleted in normal cleanup; abrupt termination relies on container disposal. Output links follow Apify storage access rules; share them only deliberately. Apify retention depends on your account/settings; delete datasets, key-value records and logs through your account when no longer needed. We do not maintain an additional transcript archive.
Failed operations send sanitized diagnostic input, exceptions and actor/build/run IDs to our private GlitchTip service for repair. Secret fields and URL queries are removed and reports are retained for 30 days. Do not submit secrets, private feed tokens or confidential audio. Public enclosures may contain publisher tracking query parameters and remain visible in your output URL.
Legality and responsible use
Use only publicly available feeds/audio you are authorized to process. Public availability does not grant redistribution rights. Respect copyright, personal-data obligations and publisher terms; avoid sensitive recordings. Human review is required before consequential use. This Actor is independent of podcast publishers, NPR, Apple, Spotify and Apify; no affiliation or endorsement is implied. Apify's standard user terms apply.
FAQ and troubleshooting
Can I paste a show page? No. Obtain the publisher's public RSS URL. Query-bearing feed URLs and credentials are rejected to reduce private-feed risk; this can also exclude some legitimate public feeds.
Why is the result empty? The feed may have no audio enclosures, the cutoff/exclusions may remove all entries, or your charge budget may be insufficient. Legitimately empty discovery is successful and uncharged.
Why did a long episode fail? Set the duration cap appropriately, up to 30 minutes. Longer episodes are outside the supported contract; the Actor never clips them silently.
Can it identify speakers or search across all podcasts? No. Use your downstream index for search; speaker diarization and podcast-directory discovery are not included.
How do I report a problem? Open an issue in this Actor's Apify Issues tab. Share the run ID and non-sensitive reproduction input, not secrets or private recordings.
Related Actors
- Audio Speech-to-Text Transcriber: transcribe individually supplied direct audio/video URLs instead of discovering RSS episodes.
- Audio Extractor — Mono Speech Files: produce preprocessing audio artifacts, not transcripts.