# RSS & Atom Feed Reader — Clean Dataset Rows (`keyman98/rss-feed-reader`) Actor

Read RSS and Atom feeds and get every item as a clean dataset row: title, link, date, author, summary, enclosures. Fast HTTP-only, no browser, failed feeds don't break the run.

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

## Pricing

from $1.00 / 1,000 feed item extracteds

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 & Atom Feed Reader

Read one or more feeds — RSS 2.0, RSS 1.0 (RDF), or Atom — and get every item as a clean, structured dataset row: title, link, published date, author, summary, categories, enclosures — instead of raw XML. Plain HTTP requests only, no browser: fast even on many feeds at once.

### What it does

For each feed URL, this Actor sends a normal HTTP GET request (the same request any feed reader would send), parses the response, and pushes one dataset row per item found. RSS 2.0, RSS 1.0 (RDF), and Atom are all supported transparently: you don't need to know which format a given URL uses.

### What you get (output fields)

One dataset row per feed item:

- `feedUrl` — the feed URL this item came from.
- `feedTitle` — title of the feed, as declared by the feed itself.
- `title` — item title.
- `link` — item link (the article/page URL).
- `published` — publish date/time, ISO 8601 UTC (`null` if the feed does not declare one).
- `updated` — last-updated date/time, ISO 8601 UTC (`null` if the feed does not declare one).
- `author` — item author, when declared.
- `summary` — item summary/description as plain text, HTML stripped, truncated to about 2000 characters.
- `contentHtml` — full item content as HTML, when the feed provides it (Atom `<content>` or RSS `content:encoded`); `null` otherwise.
- `categories` — array of category/tag names declared on the item.
- `guid` — item unique identifier as declared by the feed, falling back to its link.
- `enclosures` — array of `{ url, type, length }` for attached media files (e.g. podcast audio, images).
- `error` — set only on a feed-level error row; `null` on a normal item row.

### If a feed cannot be read

A feed that is completely unreachable (DNS failure, connection refused, timeout, persistent HTTP error), that is not valid RSS/Atom, or that parses but contains zero items becomes a **single** row: `{ "feedUrl": "...", "error": "..." }`. The rest of your feed list keeps running, the run does not fail, and you are **not charged** for that feed.

### How to use

1. **Feed URLs** — paste the RSS/Atom feed URLs you want to read.
2. **Max items per feed** — stop after this many items per feed (default 50, 1-1000). Keeps cost and run time predictable on very large feeds.
3. **Since date (optional)** — only keep items published after this date (e.g. `2026-01-01`). Items with no publish/update date on the feed are skipped when this is set, since it cannot be confirmed they are after it.
4. **Run the Actor.** Each feed item becomes one dataset row.

### Input example (JSON)

```json
{
  "feedUrls": ["https://hnrss.org/frontpage", "https://feeds.bbci.co.uk/news/rss.xml"],
  "maxItemsPerFeed": 50
}
```

### Output example (JSON)

```json
{
  "feedUrl": "https://hnrss.org/frontpage",
  "feedTitle": "Hacker News: Front Page",
  "title": "Example story title",
  "link": "https://news.ycombinator.com/item?id=1",
  "published": "2026-09-24T08:00:00Z",
  "updated": null,
  "author": null,
  "summary": "Example summary text, HTML stripped.",
  "contentHtml": null,
  "categories": [],
  "guid": "https://news.ycombinator.com/item?id=1",
  "enclosures": [],
  "error": null
}
```

### Pricing

Pay only for items actually extracted — nothing charged for a feed that could not be read. Pricing model: **pay-per-event**.

| Event | When it's charged | Price |
| --- | --- | --- |
| `item-extracted` | one feed item was parsed and pushed to the dataset | 0.001 USD |

Not charged for errors: a feed-level error row never triggers `item-extracted`.

### Limitations

- HTTP-only: does not run a browser, so feeds that require JavaScript to load (rare) are not supported.
- Duplicate feed URLs in the input are read only once.
- Dates are only as accurate as the feed itself declares; a feed with no publish date on an item leaves `published` as `null` (and excludes that item when "Since date" is set).
- No login, no CAPTCHA solving, no bypass of any site protection.

### FAQ

#### Does this support both RSS and Atom?

Yes, transparently — you paste the URL, the Actor detects the format.

#### Does this support RSS 1.0 (RDF) feeds?

Yes. RSS 2.0, RSS 1.0 (RDF), and Atom are all parsed the same way — you don't need to tell the Actor which one a feed uses.

#### Am I charged if a feed is unreachable or invalid?

No. You are only charged per item actually extracted from a feed that was successfully read.

#### What happens with duplicate feed URLs?

They are de-duplicated before the run starts; each feed URL is read once.

#### Can I limit how far back items go?

Yes, use the "Since date" input field. Items without any date on the feed are excluded when this filter is set.

#### Can I poll a feed on a schedule without getting duplicate items?

Set "Since date" and run the Actor on a schedule (Apify's built-in scheduler), moving the date forward between runs. There is no automatic deduplication built in — if you re-run with the same "Since date", you'll get the same items again.

#### Can I use this through the Apify API or an MCP server?

Yes. Like any Apify Actor, you can run it and read results through the standard Apify API, or through the Apify MCP server if you use Claude, Cursor, or another MCP-enabled client.

### Export

Results can be downloaded from the Apify dataset as JSON, CSV, or Excel, or accessed via the Apify API.

# Actor input Schema

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

Public RSS or Atom feed URLs.

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

Stop after this many items for each feed (keeps cost and run time predictable for very large feeds).

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

Only keep items published after this date (ISO 8601, e.g. "2026-01-01"). Items with no publish/update date on the feed are skipped when this is set, since it cannot be confirmed they are after it. Leave empty for no filter.

## Actor input object example

```json
{
  "feedUrls": [
    "https://hnrss.org/frontpage",
    "https://feeds.bbci.co.uk/news/rss.xml"
  ],
  "maxItemsPerFeed": 50
}
```

# Actor output Schema

## `results` (type: `string`):

All results in the default dataset (JSON, CSV, Excel).

# 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://hnrss.org/frontpage",
        "https://feeds.bbci.co.uk/news/rss.xml"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("keyman98/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://hnrss.org/frontpage",
        "https://feeds.bbci.co.uk/news/rss.xml",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("keyman98/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://hnrss.org/frontpage",
    "https://feeds.bbci.co.uk/news/rss.xml"
  ]
}' |
apify call keyman98/rss-feed-reader --silent --output-dataset

```

## MCP server setup

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