# RSS Feed Reader – Parse RSS, Atom & Podcast Feeds to JSON (`haketa/rss-feed-reader`) Actor

Read any RSS, Atom, RDF or podcast feed and get clean, structured items: title, link, author, date, full content, categories, media/enclosure and podcast duration. Auto-discovers the feed from a website URL. Filter by keyword or date. Export to JSON, CSV or Excel.

- **URL**: https://apify.com/haketa/rss-feed-reader.md
- **Developed by:** [Haketa](https://apify.com/haketa) (community)
- **Categories:** Developer tools, News, AI
- **Features:** Limited permissions
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 results

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

## RSS Feed Reader — Parse RSS, Atom, RDF & Podcast Feeds to JSON

[![Apify Actor](https://img.shields.io/badge/Apify-Actor-orange?style=flat-square\&logo=apify)](https://apify.com/haketa/rss-feed-reader)
[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg?style=flat-square)](https://apify.com/haketa/rss-feed-reader)
[![Data Format](https://img.shields.io/badge/Output-JSON%20%7C%20CSV%20%7C%20Excel-blue?style=flat-square)](https://apify.com/haketa/rss-feed-reader)
[![Architecture](https://img.shields.io/badge/Architecture-Pure%20HTTP%20%2F%20No%20Browser-purple?style=flat-square)](https://apify.com/haketa/rss-feed-reader)
[![Pagination](https://img.shields.io/badge/Pagination-1%2C000%2B%20Items%20Unlocked-brightgreen?style=flat-square)](https://apify.com/haketa/rss-feed-reader)

**The fastest, most reliable way to turn any RSS, Atom, RDF or podcast feed into clean, structured data.** This **RSS feed reader** and **RSS scraper** reads any [RSS](https://en.wikipedia.org/wiki/RSS), [Atom](https://en.wikipedia.org/wiki/Atom_\(web_standard\)), RSS 1.0 (RDF) or podcast feed — or even a plain **website URL**, from which it automatically discovers the feed — and returns every item as a tidy record: **title, link, author, publish date, summary, full content, categories, media/enclosure URL, duration and podcast metadata**. No login, no coding, no headless browser overhead. Just paste feed URLs and run.

Export every item seamlessly to **JSON, CSV, Excel, or consume directly via the Apify REST API**.

> Built for **news-monitoring teams, content aggregators, AI/RAG engineers, podcast analysts, SEO agencies, market intelligence researchers, and developers** who need a high-performance, normalized feed-to-JSON pipeline without maintaining brittle parser libraries or handling tricky feed quirks.

***

### ⚡ At a glance

| Feature | Specification |
|:---|:---|
| **Supported Standards** | RSS 2.0, RSS 1.0 (RDF), Atom 1.0, iTunes Podcast XML extensions |
| **Feed Discovery** | Automatic `<link rel="alternate">` HTML discovery from plain web URLs |
| **Throughput & Speed** | Pure-HTTP asynchronous pool (5–20 concurrent requests), ~1,500+ items/minute |
| **Pagination & Depth** | Unlocked deep ingestion (1,000+ items across feeds, controlled by `maxItems` / `maxItemsPerFeed`) |
| **Filtering Capabilities** | Keyword search (title + content body) & ISO 8601 publish date threshold |
| **Media & Audio** | Enclosure URL, MIME type, length in bytes, parsed podcast duration in seconds |
| **Output Formats** | Structured JSON, CSV, Excel (XLSX), HTML table, or live Apify Dataset API |
| **Proxy Requirement** | Standard Datacenter Proxies (automatic fresh-IP rotation on 403/429) |
| **Resource Efficiency** | Extremely lightweight (256–512 MB memory footprint, zero browser overhead) |
| **Integrations** | Zapier, Make, Google Sheets, Airbyte, LangChain, LlamaIndex, Webhooks |

***

### 🏗️ Architecture & Processing Pipeline

The Actor processes feeds through a concurrent, streaming ingestion pipeline designed for speed and resilience:

```mermaid
flowchart TD
    A["Input Feeds or Website URLs"] --> B{"Direct XML Feed?"}
    B -- "No (HTML Page)" --> C["DOM Feed Discovery: link rel=alternate"]
    B -- "Yes (XML)" --> D["Fetch Feed Stream via Datacenter Proxy"]
    C --> D
    D --> E{"HTTP 403 / 429 Rate Limit?"}
    E -- "Yes" --> F["Rotate Fresh Datacenter IP & Exponential Backoff"]
    F --> D
    E -- "No (HTTP 200)" --> G["Parse Namespaces: RSS / Atom / iTunes"]
    G --> H["Strip HTML Tags & Sanitize Entities"]
    H --> I["Apply Keyword & Since-Date Filters"]
    I --> J["Deduplicate Summary vs Full Content"]
    J --> K["Push Structured Records to Apify Dataset"]
```

***

### 🔎 Why scrape and monitor RSS feeds?

**RSS, Atom and podcast feeds** are the backbone of the open web's real-time publication network. Nearly every news organization, tech blog, industry magazine, government portal, research institute, YouTube channel and podcast network publishes one — a structured, machine-readable stream of its latest articles or episodes, broadcasted the moment new content goes live. That makes feeds the cleanest, most cost-effective, and most up-to-date source of web intelligence.

However, real-world feeds are **notoriously inconsistent and messy**:

1. **Conflicting Standards**: RSS 2.0, Atom 1.0, and RDF each structure metadata differently (e.g. `pubDate` vs `updated` vs `dc:date`).
2. **Namespace Quirks**: Media enclosures, author fields, and iTunes podcast tags are tucked away inside nested XML namespaces (`content:encoded`, `media:content`, `itunes:duration`).
3. **Markup & CDATA**: Content snippets are often entangled with unescaped HTML tags, tracker pixels, and non-standard entities.
4. **Feed Relocation**: Many sites serve redirect loops or obscure their feed endpoints behind root domains.

This **RSS feed reader** solves every edge case out of the box, returning a uniform, strictly normalized schema regardless of the feed's internal variations.

**Primary applications for RSS data extraction:**

- 📰 **Media & News Monitoring** — aggregate hundreds of regional or national publishers into a unified keyword-searchable stream.
- 🤖 **AI & RAG Knowledge Retrieval** — feed clean, plain-text article bodies straight into LLMs, text chunkers, and vector embeddings.
- 🎧 **Podcast Ecosystem Tracking** — collect audio stream URLs, episode notes, durations, and release cadences at scale.
- 🧲 **Automated Content Aggregation** — build automated Slack alerts, newsletter digests, and custom developer feeds.
- 🕵️ **Competitive & Brand Intelligence** — observe competitor blog updates and PR statements the second they go live.
- 📈 **Trend Identification** — spot emerging buzzwords across technology, finance, and healthcare publications.
- 🔁 **Workflow Automation** — push newly published items directly into Zapier, Make, Notion, or Airtable.

***

### ⚖️ Feature Comparison: Feed Reader vs Alternatives

| Capability | Haketa RSS Feed Reader | Generic Python/Node Parser | Scrape Web Pages Directly |
|:---|:---:|:---:|:---:|
| **Setup Time** | 0 minutes (ready-to-use) | Hours of library coding | Complex DOM selector tuning |
| **Feed Discovery** | ✅ Auto-detect from web URLs | ❌ Manual coding | ❌ Not applicable |
| **Podcast Parsing** | ✅ Auto duration + media URL | 🟡 Manual namespace mapping | ❌ Complex audio tag scraping |
| **HTML Sanitization** | ✅ Stripped clean text + entities | 🟡 Requires custom regex | 🟡 Requires readability libraries |
| **Content Deduplication**| ✅ Summary vs body auto-dedup | ❌ Duplicates common descriptions | ❌ Fragile extraction |
| **Proxy & CDN Resilience**| ✅ Datacenter rotation on 403/429 | ❌ Custom proxy logic required | ❌ Frequent IP bans |
| **Export Options** | ✅ JSON, CSV, Excel, REST API | ❌ Needs database or export code | ❌ Needs export pipelines |
| **Compute Cost** | 🟢 Extremely low (~$0.015/1K) | 🟡 Server infrastructure costs | 🔴 Heavy browser costs |

***

### ✨ Key Features & Capabilities

- ✅ **Universal Format Parser** — natively parses RSS 2.0, Atom 1.0, RSS 1.0 (RDF), and iTunes podcast feeds with deep namespace decoding.
- ✅ **Intelligent URL Feed Discovery** — don't have the feed URL? Supply any root website URL (e.g., `https://theverge.com`) and the Actor auto-locates the `<link rel="alternate" type="application/rss+xml">` tag.
- ✅ **Full Article Bodies vs Summaries** — extracts both concise summaries and full-text bodies (`content:encoded`), automatically eliminating duplicates when both fields share identical text.
- ✅ **Podcast & Audio Enrichment** — parses media enclosures (`mediaUrl`, `mediaType`, `mediaLength`), detects podcast status (`isPodcast: true`), and normalizes durations into integer seconds (`durationSeconds`).
- ✅ **Smart Date & Keyword Filtering** — filter feeds on ingestion with `keyword` matches across titles and bodies, or pass a `sinceDate` to pull only recent items.
- ✅ **High-Volume Deep Pagination** — collect 1,000+ items across broad publication histories with zero artificial caps or throttling.
- ✅ **Clean Text & Optional Raw HTML** — HTML tags and entities are stripped into clean Markdown-friendly prose by default, with an optional toggle (`includeHtml`) for raw markup.
- ✅ **Proxy Rotation & CDN Bypass** — lightweight pure-HTTP requests automatically retry with fresh datacenter proxy IPs when hitting temporary Cloudflare or CDN rate limits.
- ✅ **De-duplicated Input Streams** — duplicate feed URLs provided across different lists are automatically deduplicated.

***

### 🎯 High-Impact Use Cases

#### 1. Newsrooms & Media Monitoring Agencies

Track coverage across global, national, and hyper-local media outlets. Filter incoming items by company names, political topics, or industry keywords to generate executive briefs and PR sentiment analyses.

#### 2. Large Language Model (LLM) & RAG Ingestion

Retrieval-Augmented Generation systems require constant influxes of domain-specific text. This Actor provides a clean, deduplicated stream of textual knowledge with clear publish timestamps and attribution links.

#### 3. Podcast Analytics & Indexing

Extract episode release notes, direct MP3 download URLs, and exact durations across major podcast networks to power directory databases or audio transcription pipelines.

#### 4. SEO & Content Strategy Audits

Analyze the publication frequency, topical categories, and headline strategies of competing publications to optimize your own editorial roadmap.

#### 5. Automated Newsletter & Digest Publishing

Gather high-signal articles from Substack, Medium, personal engineering blogs, and corporate press centers into a single data lake to generate curated weekly digests.

***

### 🌐 Supported Source Types & Platforms

The Actor works seamlessly with feed streams generated by any modern web publishing engine:

- 📰 **Major News Portals**: BBC News, Reuters, NYT, CNN, The Guardian, Wall Street Journal.
- 💻 **Tech & Developer Blogs**: Hacker News, The Verge, TechCrunch, Ars Technica, GitHub Releases.
- ✍️ **Newsletter Platforms**: Substack (`https://domain.substack.com/feed`), Ghost blogs (`/rss/`).
- 🎙️ **Podcast Hosts**: Megaphone, Libsyn, Buzzsprout, Podbean, Anchor, Apple Podcasts XML.
- 📝 **CMS Platforms**: WordPress (`/feed/`), Drupal, Joomla, Squarespace, Webflow.
- 🎥 **Video Platforms**: YouTube Channel RSS (`https://www.youtube.com/feeds/videos.xml?channel_id=...`).

***

### 📥 Input Parameters

The Actor accepts flexible inputs designed for both quick manual runs and automated API triggers:

| Field | Type | Default | Description |
|:---|:---|:---|:---|
| `feedUrls` | Array | `["https://feeds.bbci.co.uk/news/rss.xml", ...]` | List of RSS, Atom, or podcast feed URLs (or plain website URLs for auto-discovery). |
| `startUrls` | Array | `[]` | Advanced bulk list of feed URLs loaded from a URL, Google Sheet, or Apify Request Queue. |
| `maxItems` | Integer | `0` | Maximum total records to save across all feeds (0 = unlimited). |
| `maxItemsPerFeed` | Integer | `0` | Cap on the number of items collected per feed (0 = fetch all available). Prefilled to `50` for fast trial runs. |
| `keyword` | String | `""` | Case-insensitive keyword filter applied to item titles and body texts. |
| `sinceDate` | String | `""` | Ingest only items published on or after this ISO date (e.g., `2026-01-01`). |
| `includeFullContent` | Boolean | `true` | Extract extended article bodies when available in addition to short summaries. |
| `includeHtml` | Boolean | `false` | Retain original HTML tags and formatting in the content field. |
| `proxyConfiguration` | Object | `{"useApifyProxy": true}` | Proxy configuration. Datacenter proxies are fully sufficient and cost-effective. |
| `maxConcurrency` | Integer | `8` | Parallel feed requests (recommended range: 5 to 15). |

***

### 📤 Output Dataset Schema

Each item parsed from a feed is pushed as an individual structured record.

#### 📰 Core Article & Post Fields

| Field | Type | Coverage | Description |
|:---|:---|:---|:---|
| `title` | String | 🟢 High | Clean headline or episode title. |
| `link` | String | 🟢 High | Direct canonical URL to the article or episode page. |
| `author` | String | 🟡 Conditional | Author, reporter, or content creator name (`dc:creator` / `author`). |
| `publishedAt` | String | 🟢 High | ISO 8601 UTC timestamp of publication (e.g. `2026-11-10T09:30:00.000Z`). |
| `publishedRaw` | String | 🟢 High | Unparsed date string as provided in the original feed tag (`pubDate`). |
| `summary` | String | 🟢 High | Clean, stripped text summary or introductory excerpt. |
| `content` | String | 🟡 Conditional | Full text body (`content:encoded`). Omitted if identical to summary to avoid duplication. |
| `categories` | Array | 🟡 Conditional | Array of category strings, tags, or topic classifications. |
| `guid` | String | 🟢 High | Unique permanent identifier for the feed entry. |
| `commentsUrl` | String | 🟡 Conditional | Link to the publisher's comments section when provided. |

#### 🎧 Media & Podcast Fields

| Field | Type | Coverage | Description |
|:---|:---|:---|:---|
| `isPodcast` | Boolean | 🟢 High | Flag indicating if the entry contains audio or video enclosures. |
| `mediaUrl` | String | 🟡 Conditional | Direct URL to the media asset (MP3, MP4, AAC, or image enclosure). |
| `mediaType` | String | 🟡 Conditional | MIME type of the enclosed media (e.g. `audio/mpeg`, `video/mp4`). |
| `mediaLength` | Number | 🟡 Conditional | Size of the media enclosure in bytes. |
| `durationSeconds` | Number | 🟡 Conditional | Podcast episode duration converted into integer seconds. |
| `image` | String | 🟡 Conditional | Associated article banner or podcast episode artwork URL. |

#### 🌐 Feed Context Fields

| Field | Type | Coverage | Description |
|:---|:---|:---|:---|
| `feedTitle` | String | 🟢 High | Title of the parent RSS channel or podcast show. |
| `feedLink` | String | 🟢 High | Homepage URL of the publishing organization. |
| `feedDescription`| String | 🟢 High | Tagline or editorial description of the channel. |
| `feedLanguage` | String | 🟡 Conditional | Language code declared by the feed (e.g. `en-US`, `es-ES`). |
| `feedUrl` | String | 🟢 High | The actual canonical feed URL resolved and read. |

***

### 📊 Sample Output Record

```json
{
  "feedTitle": "BBC News",
  "feedLink": "https://www.bbc.co.uk/news",
  "feedDescription": "BBC News - World",
  "feedLanguage": "en-gb",
  "feedUrl": "https://feeds.bbci.co.uk/news/world/rss.xml",
  "title": "Global Climate Accord Reaches Milestone Agreement",
  "link": "https://www.bbc.co.uk/news/world-68291034",
  "guid": "https://www.bbc.co.uk/news/world-68291034",
  "author": "BBC World Service",
  "publishedAt": "2026-11-10T12:00:00.000Z",
  "publishedRaw": "Tue, 10 Nov 2026 12:00:00 GMT",
  "summary": "Delegates from over 190 nations have concluded landmark discussions setting enforceable emissions targets for the coming decade.",
  "content": "Delegates from over 190 nations gathered this week to finalize new international environmental standards. The treaty includes dedicated funding mechanisms for emerging economies and introduces transparent carbon reporting frameworks.",
  "categories": ["World", "Environment", "Climate"],
  "mediaUrl": "https://ichef.bbci.co.uk/news/1024/branded_news/c102.jpg",
  "mediaType": "image/jpeg",
  "mediaLength": 142080,
  "durationSeconds": null,
  "image": "https://ichef.bbci.co.uk/news/1024/branded_news/c102.jpg",
  "commentsUrl": null,
  "isPodcast": false
}
```

***

### 💻 API Integration Examples

#### Node.js (Apify Client SDK)

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({
    token: process.env.APIFY_TOKEN,
});

const input = {
    feedUrls: [
        'https://feeds.bbci.co.uk/news/rss.xml',
        'https://news.ycombinator.com/rss',
        'https://www.theverge.com'
    ],
    maxItemsPerFeed: 100,
    maxItems: 500,
    keyword: 'technology',
    includeFullContent: true,
};

const run = await client.actor('haketa/rss-feed-reader').call(input);
const { items } = await client.dataset(run.defaultDatasetId).listItems();

console.log(`Successfully parsed ${items.length} feed items:`);
for (const item of items) {
    console.log(`- [${item.feedTitle}] ${item.title} -> ${item.link}`);
}
```

#### Python (Apify Client SDK)

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.getenv("APIFY_TOKEN"))

run_input = {
    "feedUrls": [
        "https://feeds.megaphone.fm/vergecast",
        "https://lexfridman.com/feed/podcast/"
    ],
    "maxItemsPerFeed": 50,
    "includeFullContent": True,
}

run = client.actor("haketa/rss-feed-reader").call(run_input=run_input)

dataset_items = client.dataset(run["defaultDatasetId"]).list_items().items
print(f"Retrieved {len(dataset_items)} podcast episodes:")

for ep in dataset_items:
    if ep.get("isPodcast"):
        print(f"Title: {ep.get('title')}")
        print(f"Audio: {ep.get('mediaUrl')} ({ep.get('durationSeconds')}s)")
```

#### cURL / Direct HTTP Request

```bash
curl -X POST "https://api.apify.com/v2/acts/haketa~rss-feed-reader/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "feedUrls": ["https://feeds.bbci.co.uk/news/rss.xml"],
    "maxItemsPerFeed": 25
  }'
```

***

### 💡 Best Practices & Pro Tips

- 🔍 **Drop In Homepages**: If you don't know the exact RSS feed URL for a site, simply paste the homepage URL (e.g. `https://techcrunch.com`). The built-in discovery engine will inspect the DOM and locate the feed link automatically.
- 📆 **Incremental Polling with `sinceDate`**: Configure a scheduled recurring run (e.g., hourly or daily) and set `sinceDate` dynamically to fetch only newly published articles without reprocessing historical records.
- 🎧 **Dedicated Podcast Pipelines**: Filter output datasets where `isPodcast: true` to feed automated transcription models or podcast indexers with verified direct audio enclosure links.
- ⚡ **Optimizing Concurrency**: For runs involving hundreds of feeds, adjust `maxConcurrency` to `12` or `15` to maximize datacenter proxy throughput and finish runs in seconds.
- 🧹 **Clean Text vs Markup**: Keep `includeHtml: false` for clean downstream ingestion into vector databases and search engines; enable `includeHtml: true` only if you require styling markup for newsletters or website embeds.
- 📦 **Bulk Loading via Google Sheets**: Point `startUrls` directly to a published Google Sheet containing thousands of RSS URLs for enterprise monitoring workflows.

***

### ❓ Frequently Asked Questions (FAQ)

**Which feed formats does this Actor handle?**
It natively handles RSS 2.0, Atom 1.0, RSS 1.0 (RDF), and standard iTunes podcast XML feeds. It automatically decodes CDATA blocks, handles character entity escapes, and accommodates slight XML syntax inconsistencies.

**Can I run this without known feed URLs?**
Yes. You can supply ordinary website URLs, and the Actor will download the HTML head section to detect standard `<link rel="alternate" type="application/rss+xml">` and `<link rel="alternate" type="application/atom+xml">` references.

**Does this require expensive residential proxies?**
No. Feeds are designed for programmatic syndicate consumption. Datacenter proxies (the default) provide top-tier speeds with near-zero failure rates. Built-in proxy rotation automatically recovers from transient CDN rate limits.

**How does deep pagination work?**
Many publishers provide archives containing hundreds or thousands of historical entries. By setting `maxItemsPerFeed: 0` and `maxItems: 0`, the Actor reads the full length of every feed stream without artificial cutoffs.

**How is episode duration calculated for podcasts?**
The Actor inspects the `<itunes:duration>` namespace, parsing either raw integer seconds (e.g. `3600`) or standard clock formats (`HH:MM:SS` or `MM:SS`) into a normalized integer in `durationSeconds`.

**Why is `content` sometimes empty while `summary` is populated?**
Many news feeds only publish short excerpts in their `<description>` tags without an extended `<content:encoded>` body. To prevent duplicate text in your dataset, `content` is set to `null` unless a genuinely distinct and richer body is supplied.

**Can I trigger webhooks when new articles appear?**
Yes. You can configure Apify Webhooks to notify your backend, Zapier, or Make whenever an execution finishes, passing the newly generated dataset items.

**What happens if a feed URL returns a 404 or becomes unavailable?**
The Actor logs a warning with the offending URL and the returned HTTP status code, then continues processing all remaining feeds in the pool without crashing or aborting the overall execution.

**Does this Actor consume headless browser compute?**
No. It operates strictly via lightweight asynchronous HTTP requests. Memory usage typically remains under 200 MB, resulting in near-instant run speeds and compute costs as low as a fraction of a cent per thousand items.

**How can I schedule this Actor to run periodically?**
In the Apify Console, open the **Schedules** tab and set up a recurring cron trigger (e.g. `0 * * * *` for hourly runs). Pair this with a dynamic `sinceDate` filter or downstream deduplication in your database to ensure you only ingest fresh updates.

**Is there any limit to the number of feeds I can pass?**
No practical limit. You can supply hundreds of feeds in `feedUrls` or upload a large text/CSV file via `startUrls`. The worker pool processes them concurrently according to your `maxConcurrency` setting.

***

### 🔗 Recommended Complementary Actors

- [Article Content Extractor — Clean Text, Markdown & Metadata](https://apify.com/haketa/article-content-extractor) — Follow article links from feeds to extract full web page markdown and reader-mode text.
- [Substack Scraper – Newsletters, Creators, Posts & Leads](https://apify.com/haketa/substack-scraper) — Deeply extract Substack newsletters, paid posts, author profiles, and community discussions.
- [Academic Paper Resolver — DOI/arXiv to Citations for AI](https://apify.com/haketa/academic-resolver) — Resolve academic preprints and citations from scientific publication feeds.
- [Tech Stack Detector — Website Tech, Email Provider & Leads](https://apify.com/haketa/tech-stack-detector) — Uncover the tech stack, DNS records, and email infrastructure behind publishing domains.

***

### 📋 Changelog

#### Version 1.2 (2026-11)

- 🚀 **Unlocked 1,000+ Deep Pagination**: Removed any artificial item caps; added global `maxItems` and feed-level `maxItemsPerFeed` controls allowing massive batch ingestion.
- ⚡ **Optimized Prefill Execution**: Tuned default prefill parameters to execute test runs in under 30 seconds with 100% item integrity.
- 🧼 **Enhanced Content Normalization**: Improved deduplication logic between summary and `content:encoded` bodies, ensuring zero duplicate text blobs.
- 🎧 **Podcast Parsing Refinements**: Added expanded duration parsing for edge-case colon-separated timestamps and multi-track enclosures.

#### Version 1.1

- 🔎 Integrated automatic feed discovery from root website URLs via `<link rel="alternate">` detection.
- 🛡️ Implemented automated fresh-IP proxy retry handling for feeds behind Cloudflare and Fastly CDNs.
- 🏷️ Added support for Dublin Core creator tags (`dc:creator`) and structured category arrays.

#### Version 1.0

- 📦 Initial release supporting RSS 2.0, Atom 1.0, and iTunes podcast XML parsing with clean JSON/CSV/Excel exports.

# Changelog

This Actor's version history is a separate document: https://apify.com/haketa/rss-feed-reader/changelog.md

# Actor input Schema

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

One RSS / Atom / RDF / podcast feed URL per line. You can also paste a plain website URL — the Actor will find its feed automatically.

## `startUrls` (type: `array`):

Optional. Load many feed URLs from a file, URL, Google Sheet or Request Queue.

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

Maximum total items to output across all feeds. Set to 0 for unlimited (all available items).

## `maxItemsPerFeed` (type: `integer`):

Maximum number of items to return from each feed. Set to 0 for all available items.

## `keyword` (type: `string`):

Optional. Only return items whose title or content contains this text (case-insensitive).

## `sinceDate` (type: `string`):

Optional. Only return items published on or after this date, e.g. 2026-07-01. Leave blank for all.

## `includeFullContent` (type: `boolean`):

Include the full article/episode content as plain text (in addition to the short summary).

## `includeHtml` (type: `boolean`):

Also include the original HTML of the content. Turn off for clean text only.

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

Proxy settings. Datacenter proxies (the default) are more than enough for reading feeds.

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

How many feeds to read in parallel. Recommended: 5–15.

## Actor input object example

```json
{
  "feedUrls": [
    "https://www.theverge.com/rss/index.xml"
  ],
  "startUrls": [],
  "maxItems": 0,
  "maxItemsPerFeed": 50,
  "includeFullContent": true,
  "includeHtml": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 8
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

Download every feed item collected in this run (JSON, CSV, Excel).

## `runUrl` (type: `string`):

Open this run in the Apify Console.

## `title` (type: `string`):

Item title

## `link` (type: `string`):

Item URL

## `author` (type: `string`):

Item author

## `publishedAt` (type: `string`):

Publish date (ISO 8601)

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

Short summary (plain text)

## `content` (type: `string`):

Full content (plain text)

## `categories` (type: `string`):

Item categories / tags

## `feedTitle` (type: `string`):

Source feed title

## `isPodcast` (type: `string`):

Whether the item has audio/video media

## `mediaUrl` (type: `string`):

Enclosure / media URL (audio, video, image)

## `durationSeconds` (type: `string`):

Podcast episode duration in seconds

## `image` (type: `string`):

Item image URL

## `commentsUrl` (type: `string`):

Comments page URL

## `guid` (type: `string`):

Unique item identifier

## `feedUrl` (type: `string`):

Source feed URL

# 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.bbci.co.uk/news/rss.xml",
        "https://news.ycombinator.com/rss"
    ],
    "startUrls": [],
    "maxItemsPerFeed": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("haketa/rss-feed-reader").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.bbci.co.uk/news/rss.xml",
        "https://news.ycombinator.com/rss",
    ],
    "startUrls": [],
    "maxItemsPerFeed": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("haketa/rss-feed-reader").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.bbci.co.uk/news/rss.xml",
    "https://news.ycombinator.com/rss"
  ],
  "startUrls": [],
  "maxItemsPerFeed": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call haketa/rss-feed-reader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,haketa/rss-feed-reader"
        }
    }
}
```

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/2mpZgHbIC8eXGLPgI/builds/rXB9x8UI1UeAp4HYq/openapi.json
