# RSS Feed Reader - Any RSS/Atom Feed to JSON (`rowfeed/rss-feed-reader`) Actor

Convert any RSS 2.0 or Atom feed URL into clean JSON: one row per item with title, link, published date, author, summary and categories. Bad feeds become error rows, not crashes.

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

## Pricing

$0.50 / 1,000 items

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?

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

Turn **any RSS 2.0 or Atom feed** into clean, structured JSON: **one row per item**, ready for a spreadsheet, a database, or an AI agent's context window. Give it your own feed URLs — a news site, a job board, a podcast, a blog, a changelog — and get back title, link, publish date, author and summary for every item, in seconds, with no login and no browser.

Built for **automation/no-code workflows** (n8n, Make, Zapier) that need an RSS-to-JSON step instead of running their own parser, **researchers and analysts** who track many feeds and need one consistent schema across all of them, and **AI agents** that need to hand a feed URL to a tool and get structured items back instead of raw XML.

This Actor never scrapes a website — you bring your own feed URLs. There is no source to break, no ToS to worry about, and no proxy involved: just an HTTP fetch and a standards-based feed parse (RSS 2.0 and Atom, both handled).

### What you get

- **One row per feed item**, not one blob per feed — `title`, `link`, `published` (ISO 8601 UTC), `author`, `summary` (HTML stripped), `categories` and podcast-style `enclosure_url`/`enclosure_type`, so downstream filtering and sorting is trivial.
- **Both RSS 2.0 and Atom** parsed with the same schema — mix a WordPress RSS feed, a Substack Atom feed and a podcast RSS feed in one run and get identical rows back.
- **Errors instead of crashes** — a bad URL, a 404, a timeout or a non-XML response becomes a single unbilled error row (`error`, `errorMessage`), and the rest of your feed list keeps going.

### Sample row

A real row from a default run against BBC News:

```json
{
  "feed_url": "https://feeds.bbci.co.uk/news/rss.xml",
  "feed_title": "BBC News",
  "id": "https://www.bbc.co.uk/news/articles/cq5xjlvn71lo#1",
  "title": "UK economy grew faster than expected in July",
  "link": "https://www.bbc.co.uk/news/articles/cq5xjlvn71lo?at_medium=RSS&at_campaign=rss",
  "published": "2026-09-11T07:45:18+00:00",
  "updated": null,
  "author": null,
  "summary": "The economy expanded by 0.4%, official figures show, whereas economists had predicted no growth.",
  "content": null,
  "categories": [],
  "enclosure_url": null,
  "enclosure_type": null,
  "scraped_at": "2026-09-11T07:55:32+00:00"
}
```

Items are sorted **newest first** across every feed you supply, combined into one dataset.

### Filters

| Input | Default | What it does |
|---|---|---|
| `feedUrls` | We Work Remotely + Hacker News + BBC News | Your own RSS 2.0 or Atom feed URLs. |
| `maxItemsPerFeed` | `100` | Stop after this many items per feed, in the feed's own order. |
| `includeContent` | `false` | Add the item's full content (RSS `content:encoded` / Atom `content`) to every row, not just the short `summary`. Off by default to keep rows small — most feeds only publish a summary anyway. |
| `newerThan` | unset | Optional ISO 8601 date; items published before it are dropped. Items with no parseable date are always kept. |

### No personal data beyond the feed's own byline

The only person-identifying field is `author` — and only when the feed itself publishes a byline (a blog post's author name, a podcast host). Nothing is inferred, looked up or enriched; you get exactly what the feed already makes public. Free-text fields (`summary`, `content`) are the feed's own published text and may contain whatever the publisher wrote, such as a job posting's contact address.

### Pricing

Pay per event, no subscription: **$0.50 per 1,000 items**. A default run (3 feeds, ~145 items) costs about 7 cents. Error rows (a dead feed URL) are never charged. If every feed in your list fails, the run is marked failed rather than quietly returning nothing, and you are billed for nothing.

### Use it from your tools

- **API and SDKs** — call it via the Apify API or the official Python/JavaScript clients: one call to start the run, one to fetch the item rows as JSON, CSV or Excel.
- **n8n, Make and Zapier** — trigger runs and feed the items into a workflow through Apify's integration for each.
- **AI agents and MCP** — eligible for agentic use via Apify's MCP server with pay-per-event pricing, so an agent can hand it a feed URL mid-task and pay only for the items it actually got back.

### Details

- **Fetching**: plain `httpx` GET over http/https only (no proxy, no browser). Requests are capped at 20 MB and time out after 30 s; 429 and 5xx responses are retried with exponential backoff (5 tries), 404/401/403 are not.
- **Parsing**: stdlib `xml.etree.ElementTree` against both the RSS 2.0 `<rss><channel><item>` shape and the Atom `<feed><entry>` shape. A response that isn't recognizable as either becomes an unbilled `not_xml` error row instead of being handed to downstream code.
- **HTML stripping**: `summary` (and `content` when `includeContent` is on) has HTML tags removed and whitespace collapsed, so you get plain text, not markup.
- **Run stats**: the `STATS` record in the run's key-value store holds per-feed and per-item counts, including items dropped by `newerThan`.
- **Not affiliated** with any feed source you point it at — you supply your own feed URLs; nothing is scraped from a website.

# Actor input Schema

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

Your own RSS 2.0 or Atom feed URLs. Each feed is fetched once and every item becomes one row. A bad URL, a timeout or a non-XML response becomes an unbilled error row instead of stopping the run.

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

Stop after this many items per feed (in the feed's own order). Each item is one `item` event ($0.50 per 1,000).

## `includeContent` (type: `boolean`):

Add the item's full content (RSS content:encoded / Atom content) to every row, not just the short summary. Off by default to keep rows small.

## `newerThan` (type: `string`):

Optional ISO 8601 date/time, e.g. 2026-01-01. Items published before this are dropped. Items with no parseable published date are always kept. Leave blank for no filter.

## Actor input object example

```json
{
  "feedUrls": [
    "https://hnrss.org/frontpage"
  ],
  "maxItemsPerFeed": 100,
  "includeContent": false
}
```

# Actor output Schema

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

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

# Run the Actor and wait for it to finish
run = client.actor("rowfeed/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 '{}' |
apify call rowfeed/rss-feed-reader --silent --output-dataset

```

## MCP server setup

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