# RSS Feed Reader & Scraper — Bulk RSS, Atom & Podcast to JSON (`ntriqpro/rss-feed-reader`) Actor

Bulk RSS feed reader and scraper. Paste up to 100 RSS, Atom, JSON Feed or podcast URLs (or site URLs — feeds are auto-discovered) and get one clean JSON row per item: title, link, ISO date, author, text summary, HTML content, tags, audio enclosure, GUID, plus a per-feed summary with a verdict.

- **URL**: https://apify.com/ntriqpro/rss-feed-reader.md
- **Developed by:** [daehwan kim](https://apify.com/ntriqpro) (community)
- **Categories:** News, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

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

## RSS Feed Reader & Scraper — Bulk RSS, Atom & Podcast to JSON

**Paste a list of feeds, get every item back as clean JSON.** This **RSS feed
reader** and **RSS scraper** reads up to 100 **RSS, Atom, JSON Feed and podcast
feeds** in one run and returns one flat row per item — title, link, ISO-8601
date, author, HTML-stripped summary, full HTML content, tags, audio enclosure
and GUID — plus a per-feed summary with a one-line verdict such as
`TechCrunch — 12 new item(s) since 2026-08-30, latest 2026-09-02`.

Hand it a plain website URL and it finds the feed for you. Schedule it, pipe it
into a webhook, Google Sheets, Zapier or Make, or pull the dataset through the
Apify API — everything you need to turn a pile of feeds into a monitoring,
newsletter or research pipeline.

Powered by **[feedparser](https://github.com/kurtmckee/feedparser)**, the Python
feed parser that has handled every feed dialect — and every broken feed — for
twenty years.

> **Unofficial.** This Actor wraps the open-source feedparser library
> (BSD-2-Clause) and is **not affiliated with, endorsed by, or sponsored by** any
> publisher, podcast network or feed provider. See `LICENSE-NOTICE.md`.

### Why use RSS Feed Reader & Scraper?

- **Bulk, not one feed at a time** — up to 100 feed URLs per run, fetched in
  parallel. A run over 20 news feeds finishes in seconds.
- **Every dialect** — RSS 0.9x / 1.0 / 2.0, Atom 0.3 / 1.0, JSON Feed, CDF,
  iTunes and Media RSS namespaces. Malformed XML is repaired where possible and
  reported in `parserWarning`, not dropped.
- **Feed discovery** — give it `https://www.bbc.co.uk/news` and it reads the
  feed the page advertises (`<link rel="alternate">`), falling back to
  well-known paths such as `/feed` and `/rss.xml`.
- **Normalised rows** — the same fields for every item, regardless of the source
  format: `published` is always ISO-8601 UTC, `summary` is always plain text,
  `contentHtml` keeps the original markup.
- **Podcast-aware** — `enclosureUrl`, `enclosureType`, `enclosureLength` and
  `hasAudio` on every episode; `isPodcast` on the feed summary.
- **A verdict, not just rows** — each feed gets a `feed-summary` row with
  `itemCount`, `lastPublished`, `isPodcast` and a one-line `headline`, and the
  run gets one summary row on top. Point a Slack or email integration at those
  rows and you have a feed monitor.
- **Incremental** — set `since` to an ISO date and only newer items come back.
  Combine with a schedule to poll feeds hourly and pay only for what is new.
- **Honest and light** — one request per feed, an honest bot User-Agent, no
  browser, no login, no bypassing of bot protection. A publisher that blocks
  the request is reported in a notice row with the HTTP status.

### How to use RSS Feed Reader & Scraper

1. Paste your feed or site URLs into **Feed or site URLs**.
2. Optionally set **Max items per feed** (default 50) and **Only items
   published since** (e.g. `2026-08-30`).
3. Click **Start** and read the results in the **Output** tab, or pull them
   through the Apify API. Filter on `rowType == "item"` for the articles.

### Input

| Field | Type | Description |
|---|---|---|
| `feedUrls` | array | Up to 100 feed or site URLs. Required. |
| `maxItemsPerFeed` | integer | Newest items kept per feed, 1–500. Default `50`. |
| `discoverFeeds` | boolean | Find the feed behind a website URL. Default `true`. |
| `since` | string | ISO-8601 date or datetime; older items are skipped, undated items are kept. |

```json
{
  "feedUrls": [
    "https://feeds.bbci.co.uk/news/rss.xml",
    "https://techcrunch.com/feed/",
    "https://hnrss.org/frontpage",
    "https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml",
    "https://www.theguardian.com/world/rss",
    "https://stratechery.com/feed/"
  ],
  "maxItemsPerFeed": 50,
  "discoverFeeds": true,
  "since": "2026-08-30"
}
```

### Output

Every dataset row carries a `rowType`:

| `rowType` | What it is | Charged |
|---|---|---|
| `item` | One feed item (article, post, episode) | yes |
| `feed-summary` | One per readable feed — counts, `lastPublished`, `isPodcast`, `headline` | no |
| `notice` | Status rows: `summary` (whole run), `feed-failed`, `feed-empty`, `no-items-since`, `no-input`, `targets-truncated`, `free-plan-cap`, `charge-limit-reached`, `billing-unavailable`, `invalid-input` | no |

Bad input or an unreadable feed ends the run as SUCCEEDED with a notice row, so
scheduled runs keep going.

```json
{
  "rowType": "item",
  "feedTitle": "BBC News",
  "feedUrl": "https://feeds.bbci.co.uk/news/rss.xml",
  "sourceUrl": "https://www.bbc.co.uk/news",
  "title": "Iran attacks US bases in Middle East after reports US strike killed five at wedding party",
  "link": "https://www.bbc.co.uk/news/articles/cj06q4ynpmjo",
  "published": "2026-09-02T05:12:07+00:00",
  "publishedRaw": "Wed, 02 Sep 2026 05:12:07 GMT",
  "author": null,
  "summary": "The Iranian Red Crescent says a child was among those killed when shrapnel from a US strike hit a wedding.",
  "contentHtml": "<p>The Iranian Red Crescent says a child was among those killed …</p>",
  "tags": ["World"],
  "enclosureUrl": null,
  "enclosureType": null,
  "enclosureLength": null,
  "hasAudio": false,
  "guid": "https://www.bbc.co.uk/news/articles/cj06q4ynpmjo#0",
  "language": null,
  "commentsUrl": null,
  "imageUrl": "https://ichef.bbci.co.uk/ace/standard/240/cpsprodpb/38d2/live/03a25690.jpg",
  "fetchedAt": "2026-09-02T06:04:03.160062+00:00"
}
```

A podcast episode looks the same, with `enclosureUrl` pointing at the audio
file, `enclosureType` such as `audio/mpeg` and `hasAudio: true`.

The `feed-summary` row for that feed:

```json
{
  "rowType": "feed-summary",
  "feedTitle": "BBC News",
  "feedUrl": "https://feeds.bbci.co.uk/news/rss.xml",
  "sourceUrl": "https://www.bbc.co.uk/news",
  "headline": "BBC News — 12 new item(s) since 2026-08-30, latest 2026-09-02",
  "fetchStatus": "ok",
  "itemCount": 12,
  "itemsInFeed": 35,
  "itemsFilteredBySince": 23,
  "audioItemCount": 0,
  "lastPublished": "2026-09-02T05:12:07+00:00",
  "isPodcast": false,
  "feedLink": "https://www.bbc.co.uk/news",
  "feedDescription": "BBC News - News Front Page",
  "feedLanguage": "en-gb",
  "feedVersion": "rss20",
  "feedImageUrl": "https://news.bbcimg.co.uk/nol/shared/img/bbc_news_120x60.gif",
  "discoveredVia": "link-alternate",
  "parserWarning": null
}
```

The run summary row (`noticeCode: "summary"`) carries `feedsOk`, `feedsEmpty`,
`feedsFailed`, `itemsDelivered`, `audioItemCount`, `podcastFeeds` and a
`fetchStatusDistribution` such as `{"ok": 5, "http-403": 1}`.

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

### Data table

| Field | Description |
|---|---|
| `rowType` | `item`, `feed-summary` or `notice` |
| `feedTitle` / `feedUrl` / `sourceUrl` | The feed's title, the URL actually read, and the URL you supplied |
| `title` / `link` / `guid` | Item title (entities decoded, tags stripped), permalink and unique id |
| `published` / `publishedRaw` | ISO-8601 UTC timestamp (published, else updated) and the raw string from the feed |
| `author` | Author name or email as given by the feed |
| `summary` | Plain-text summary with HTML removed |
| `contentHtml` | Full item content as HTML, when the feed carries it |
| `tags` | Category / tag terms |
| `enclosureUrl` / `enclosureType` / `enclosureLength` / `hasAudio` | Attached media — audio for podcasts, video or files for other feeds |
| `imageUrl` | Thumbnail or media image, when present |
| `language` / `commentsUrl` | Item language and comments link, when present |
| `fetchedAt` | UTC timestamp of the read |
| `headline` | One-line verdict on the feed-summary row |
| `fetchStatus` | `ok`, `http-403`, `http-404`, `timeout`, `not-a-feed`, `no-feed-found`, … |
| `itemCount` / `itemsInFeed` / `itemsFilteredBySince` | Items delivered, items present, items skipped by `since` |
| `lastPublished` / `isPodcast` / `feedVersion` / `discoveredVia` / `parserWarning` | Feed-level facts |

### Pricing

Pay-per-event: **$0.005 per run** plus **$0.002 per feed item**. Twenty feeds
returning 500 items cost $1.01 for that run. Every `item` row written to the
dataset is charged; `feed-summary` and `notice` rows are not. Apify platform
compute is billed separately per your plan.

**Free-plan runs return up to 25 items**, shared evenly across the feeds you
supplied; upgrade your Apify plan to receive the full result set in one run.

### Tips

- Schedule the Actor and set `since` to the time of the previous run to build
  an incremental feed monitor that only returns — and only charges for — new
  items.
- Feed discovery tries the page's own `<link rel="alternate">` first, then
  `/feed`, `/rss`, `/rss.xml`, `/atom.xml`, `/feed.xml`, `/index.xml`. For
  sites that hide their feed elsewhere, paste the feed URL directly.
- `maxItemsPerFeed` counts the newest items; podcast archives with hundreds of
  episodes can be pulled in full by raising it to 500.
- Filter on `hasAudio == true` to keep only podcast episodes across a mixed
  list of feeds.
- If a publisher answers `http-403` or `http-429`, that is the publisher's
  bot policy; the Actor reports it and moves on rather than trying to get
  around it.

### FAQ, disclaimers, and support

**Does it fetch the full article?** No. It returns what the feed publishes —
for many feeds that is the full `contentHtml`, for others a summary and a link.
Pair it with a content-extraction Actor for the article body.

**Does it work with JSON Feed and podcasts?** Yes. JSON Feed is parsed like any
other format; podcast episodes carry their audio enclosure and the feed summary
flags `isPodcast`.

**Why did a feed come back as `feed-failed`?** The `fetchStatus` says why:
`http-403` means the publisher blocks automated readers, `timeout` means no
answer within 15 seconds, `not-a-feed` means the URL served something other than
a feed and discovery was off or found nothing.

**Privacy & data responsibility.** The Actor reads only publicly syndicated
content. **You are the data controller** for the feed list you submit and for
any personal data the feeds contain (author names, for instance); ntriqpro is a
**data processor** acting solely on your instructions. Results are written only
to your own run's dataset and **we do not store them**. You are responsible for
the terms of service and copyright of every site you read, and for GDPR, CCPA and
other applicable laws in how you reuse the content.

**Open-source licence.** Built on **feedparser** (BSD-2-Clause) by Kurt McKee
and Mark Pilgrim, with **requests** (Apache-2.0). It is an independent
integration, not an official distribution. See `LICENSE-NOTICE.md`.

**Found a bug or want a feature?** Use the **Issues** tab. Custom solutions
available.

*Used this Actor? A sentence in the **Reviews** tab about what you used it for
helps the next person decide.*

### Works well with

- **[lighthouse-website-audit](https://apify.com/ntriqpro/lighthouse-website-audit)** — Score the sites behind the feeds you just read for performance, SEO and accessibility in one batch.
- **[whois-domain-lookup](https://apify.com/ntriqpro/whois-domain-lookup)** — Check who registers each publisher domain, how old it is and when it expires before you cite or syndicate it.

Every run of this Actor also returns these suggestions in the `nextSteps` field of its summary row.

# Actor input Schema

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

Up to 100 RSS, Atom, JSON Feed or podcast feed URLs. A plain website URL (e.g. https://www.bbc.co.uk/news) also works when feed discovery is on — the feed advertised by the page is read instead. Free plan: each run returns up to 25 results. Paid Apify plans receive the full result set.

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

Newest items kept from each feed. Most feeds publish 10 to 50 items; podcast feeds can carry hundreds.

## `discoverFeeds` (type: `boolean`):

When a URL returns an HTML page instead of a feed, look for the feed it advertises (<link rel="alternate">) and a few well-known paths such as /feed and /rss.xml. Turn off to read only exact feed URLs.

## `since` (type: `string`):

Optional ISO-8601 date or datetime, e.g. 2026-08-30 or 2026-08-30T12:00:00Z. Older items are skipped; items with no date are kept.

## Actor input object example

```json
{
  "feedUrls": [
    "https://feeds.bbci.co.uk/news/rss.xml",
    "https://techcrunch.com/feed/",
    "https://hnrss.org/frontpage",
    "https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml",
    "https://www.theguardian.com/world/rss",
    "https://stratechery.com/feed/"
  ],
  "maxItemsPerFeed": 50,
  "discoverFeeds": true
}
```

# Actor output Schema

## `items` (type: `string`):

No description

# 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://techcrunch.com/feed/",
        "https://hnrss.org/frontpage",
        "https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml",
        "https://www.theguardian.com/world/rss",
        "https://stratechery.com/feed/"
    ],
    "maxItemsPerFeed": 50,
    "discoverFeeds": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("ntriqpro/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://techcrunch.com/feed/",
        "https://hnrss.org/frontpage",
        "https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml",
        "https://www.theguardian.com/world/rss",
        "https://stratechery.com/feed/",
    ],
    "maxItemsPerFeed": 50,
    "discoverFeeds": True,
}

# Run the Actor and wait for it to finish
run = client.actor("ntriqpro/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://techcrunch.com/feed/",
    "https://hnrss.org/frontpage",
    "https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml",
    "https://www.theguardian.com/world/rss",
    "https://stratechery.com/feed/"
  ],
  "maxItemsPerFeed": 50,
  "discoverFeeds": true
}' |
apify call ntriqpro/rss-feed-reader --silent --output-dataset

```

## MCP server setup

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