# RSS & Atom Feed Reader + Auto-Discovery (News Monitor) (`integriapps/rss-feed-reader`) Actor

Read RSS 2.0, RSS 1.0/RDF, Atom and JSON Feed from feed URLs or any website (auto-discovers its feed). Clean, stable JSON per item, keyword and date filters, and an only-new mode that remembers what you already got, for scheduled news alerts and AI agents. Pay per item. By IntegriApps.

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

## Pricing

$0.50 / 1,000 feed item returneds

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 + Auto-Discovery (News Monitor)

Read **RSS 2.0, RSS 1.0 (RDF), Atom and JSON Feed** from feed URLs — or just paste a **website URL** and the Actor **auto-discovers its feed**. Every item comes back as the **same clean, stable JSON** no matter the feed format: title, link, author, ISO dates, plain-text summary, categories, images and podcast enclosures. Filter by **keywords** and **date**, and switch on **only-new mode** to get just the items you have not seen yet — ideal for **scheduled news alerts, RSS-to-Slack/email automations, content monitoring and AI agents (MCP)**.

Part of [IntegriApps MicroApps](https://integriapps.com/microapps/). Support Sunday to Friday.

### What it does

- **All feed formats, one output:** RSS 2.0 (incl. `content:encoded`, `dc:creator`, Media RSS, iTunes enclosures), RSS 1.0/RDF, Atom 1.0 (incl. `xhtml` content and `xml:base`) and JSON Feed 1.0/1.1, normalized to one schema.
- **Feed auto-discovery:** give a normal web page (e.g. `https://github.blog/`) and it finds the feed from `<link rel="alternate">`, then tries common paths (`/feed`, `/rss.xml`, `/atom.xml`, `/feed.xml`, `/index.xml`, `/rss`, `/feed.json`). Comment feeds are tried last.
- **Filters:** include/exclude keywords (title, summary and categories, case-insensitive), `sinceHours` or `sinceDate`, max items per feed and per run. Items are sorted newest first.
- **Only-new mode for alerts:** remembers item IDs between runs in a **named key-value store in your own Apify account**, so a scheduled run returns (and charges) only new items. It also sends `If-None-Match` / `If-Modified-Since`, so unchanged feeds cost almost nothing.
- **Per-feed errors never crash the run:** a broken, blocked or missing feed becomes one record with a `status` (`error`, `blocked_by_robots_txt`, `no_feed_found`, `not_a_feed`, `parse_error`) and the other feeds keep going. Errors are not charged.
- **Tolerant parser:** handles BOMs, comments before the root, CDATA, HTML entities, relative links and many date formats; malformed feeds return whatever items can be read instead of failing.
- **Polite by design:** identifiable User-Agent (`IntegriAppsRssFeedReader`), respects **robots.txt** (incl. `Crawl-delay`), retries with exponential backoff and `Retry-After`, timeouts, limited concurrency. Plain HTTP only — **no browser, no proxies, no bypassing of blocks, logins or paywalls**. Runs in 128–256 MB.
- **No article scraping:** it returns only what the feed itself publishes. `contentHtml` is included only if you ask for it and only when the feed contains full content.

### Use cases

- **News and brand monitoring:** watch tech blogs, newsrooms, government and science agencies (e.g. NASA), and get only new items that mention your keywords.
- **Alerts:** schedule the Actor every 15–60 minutes with only-new mode and send new items to Slack, Teams, email or a webhook via Zapier, Make or n8n.
- **AI agents and RAG:** give an agent an MCP tool that turns "what's new on this site?" into structured JSON; feed fresh items into a vector database.
- **Podcast and release tracking:** collect episodes (audio enclosures) or project release feeds that allow automated access.

### Input

| Field | Description | Default |
|---|---|---|
| `startUrls` | Feed URLs or website URLs (up to 1,000) | — (empty = free 5-item demo with the NASA news releases feed) |
| `maxItemsPerFeed` | Newest items per feed after filters (1–1,000) | 50 |
| `maxTotalItems` | Cap of items in the whole run | 5,000 |
| `includeKeywords` / `excludeKeywords` | Words or phrases matched in title, summary and categories | — |
| `sinceHours` / `sinceDate` | Keep only recent items (items without a date are dropped when used) | — |
| `onlyNew` | Return only items not returned before (state kept between runs) | false |
| `stateStoreName` | Named key-value store used by only-new mode | `rss-feed-reader-state` |
| `autoDiscover` | Discover feeds from HTML pages | true |
| `maxFeedsPerSite` | Feeds to read when a site lists several | 1 |
| `includeContent` | Add `contentHtml` with the full HTML that the feed publishes | false |
| `maxSummaryChars` | Plain-text summary length (0 = no limit) | 500 |
| `maxConcurrency` | Feeds fetched in parallel (1–10) | 5 |

Example — AI news alert from three sources, only new items from the last 3 days:

```json
{
  "startUrls": [
    { "url": "https://feeds.bbci.co.uk/news/technology/rss.xml" },
    { "url": "https://feeds.npr.org/1019/rss.xml" },
    { "url": "https://simonwillison.net/" }
  ],
  "includeKeywords": ["AI", "LLM", "model"],
  "excludeKeywords": ["sponsored"],
  "sinceHours": 72,
  "onlyNew": true,
  "stateStoreName": "ai-news-alert"
}
```

### Output

One dataset item per feed entry. Real item from a run (NPR technology RSS):

```json
{
  "status": "ok",
  "feedUrl": "https://feeds.npr.org/1019/rss.xml",
  "feedTitle": "NPR Topics: Technology",
  "feedFormat": "rss2",
  "siteUrl": "https://www.npr.org/templates/story/story.php?storyId=1019",
  "language": "en",
  "guid": "https://www.npr.org/2026/11/04/nx-s1-6026597/review-legend-of-zelda-ocarina-of-time-remake-switch-2",
  "title": "Review: The Legend of Zelda: Ocarina of Time remake is superb, streamlined and safe",
  "link": "https://www.npr.org/2026/11/04/nx-s1-6026597/review-legend-of-zelda-ocarina-of-time-remake-switch-2",
  "author": "James Perkins Mastromarino",
  "published": "2026-11-04T11:00:00.000Z",
  "updated": null,
  "summary": "Nintendo's new Ocarina of Time remake enshrines its place in the gaming canon for generations to come. But despite its stupendous production values, the game left me feeling oddly bereft.",
  "categories": [],
  "enclosures": [],
  "imageUrl": "https://npr.brightspotcdn.com/dims3/default/strip/false/crop/1920x1080+0+0/resize/1920x1080!/...jpg",
  "commentsUrl": null,
  "inputUrl": "https://feeds.npr.org/1019/rss.xml",
  "scrapedAt": "2026-11-04T17:06:58.890Z"
}
```

Website URLs work too: the input `https://simonwillison.net/` was resolved to `https://simonwillison.net/atom/everything/` (Atom) and returned items with `categories` such as `["machine-learning", "ai", "llms"]`.

A feed that could not be read is one record like this (not charged):

```json
{ "status": "no_feed_found", "inputUrl": "https://example.com/", "feedUrl": null, "httpStatus": null,
  "error": "No RSS/Atom/JSON feed found on the page (<link rel=\"alternate\">) or at common paths (...)" }
```

Fields: `status`, `feedUrl`, `feedTitle`, `feedFormat` (`rss2`, `rdf`, `atom`, `jsonfeed`), `siteUrl`, `language`, `guid` (feed ID, or a stable hash if the feed has none), `title`, `link`, `author`, `published` / `updated` (ISO 8601 UTC or null), `summary` (plain text), `contentHtml` (only with `includeContent`), `categories`, `enclosures` (`url`, `type`, `length`), `imageUrl`, `commentsUrl`, `inputUrl`, `scrapedAt`.

The key-value store record `RUN_SUMMARY` has per-feed counts (items in feed, returned, filtered, duplicates, not modified, errors). Export the dataset as JSON, JSONL, CSV, Excel, XML or RSS from Apify Console or the API.

### Pricing

**Pay per event: USD 0.0005 per item returned** (USD 0.50 per 1,000 items), plus Apify's standard tiny Actor start fee. No monthly rental and no per-run fee from us. **Not charged:** feed errors, robots.txt blocks, feeds without new items, items removed by your filters and items skipped as already seen in only-new mode. You can cap spending with the run's maximum charge setting; the Actor stops cleanly at the limit and items it could not return are kept as "not seen" for the next run.

Example: 20 feeds checked every hour in only-new mode that produce ~100 new items per day cost about USD 1.50 per month in item events.

### Use it from your code

```bash
curl -X POST "https://api.apify.com/v2/acts/integriapps~rss-feed-reader/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"startUrls":[{"url":"https://www.nasa.gov/news-release/feed/"}],"maxItemsPerFeed":5}'
```

- **JavaScript / Python:** use the official `apify-client` (`client.actor("integriapps/rss-feed-reader").call(input)`).
- **Zapier, Make, n8n:** use the Apify app/node "Run Actor" (or a saved Task with a schedule), then loop over the dataset items and post them to Slack, email, Sheets or a webhook. Use `onlyNew: true` so each run only sends new items.
- **AI agents (MCP):** add `integriapps/rss-feed-reader` as a tool in the [Apify MCP server](https://mcp.apify.com/) so Claude, ChatGPT, Cursor or any MCP client can ask "what's new on these sites about X?".
- **Schedules and webhooks:** create a Task with your feeds, schedule it in Apify, and add a webhook on "run succeeded" to push results anywhere.

### FAQ

**Does it download the full articles?** No. It returns only what the feed publishes. If the feed contains full content you can get it in `contentHtml`; otherwise you get the feed's summary and the link. Respect each publisher's terms when you reuse content.

**Why was a feed blocked?** Some sites disallow automated access to their feeds in robots.txt (for example, GitHub's robots.txt disallows `*.atom` paths), and we respect that. Those inputs come back as `blocked_by_robots_txt` and are free. If robots.txt cannot be fetched because of a server or network error, the feed is skipped to stay on the safe side.

**How does only-new mode remember items?** It stores item IDs (the feed's `guid`/`id`, else the link) per feed and per keyword set in the named key-value store you choose, in your account. Up to 5,000 IDs per feed are kept. On the first run all current items are new. Items cut by `maxItemsPerFeed` are also marked as seen, so later runs do not trickle old items. Use a different `stateStoreName` per alert.

**What about items without a date?** They are kept (sorted last) unless you use `sinceHours` or `sinceDate`, in which case they are dropped.

**A feed works in my browser but returns `error` (e.g. HTTP 403/419/429).** Some sites rate-limit or block requests from cloud servers. The Actor retries with backoff and then reports the feed as `error` (free) instead of trying to get around the block. Running less often or with lower concurrency usually helps.

**Does it render JavaScript, use proxies or get around blocks?** No. Feeds are plain XML/JSON, so a fast HTTP request is enough. It never uses proxies or headless browsers and never tries to bypass bot protection, logins or paywalls.

**Which websites can be auto-discovered?** Any site that links its feed in the HTML `<head>` with the standard `<link rel="alternate">` tag (tested with WordPress sites such as github.blog and techcrunch.com, and with simonwillison.net; most blog platforms and news sites add it) or serves one at a common path. Sites without any feed return `no_feed_found`.

**Does it parse podcasts?** Yes, audio/video enclosures (RSS `enclosure`, Media RSS, Atom `rel="enclosure"`, JSON Feed attachments) are returned in `enclosures`.

### Changelog

See [CHANGELOG.md](./CHANGELOG.md).

Part of [IntegriApps MicroApps](https://integriapps.com/microapps/) — small tools by IntegriApps, a SaaS for SMBs. Support Sunday to Friday.

# Changelog

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

# Actor input Schema

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

RSS/Atom/RDF/JSON Feed URLs, or normal website URLs (the Actor auto-discovers the site's feed). Up to 1,000 per run. If empty, a free demo reads 5 items from the NASA news releases feed.

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

Newest items returned per feed after filters (1–1,000). Each returned item is one charged event.

## `maxTotalItems` (type: `integer`):

Hard cap of items returned in the whole run (spending guard).

## `includeKeywords` (type: `array`):

Optional. Keep only items whose title, summary or categories contain at least one of these words or phrases (case-insensitive).

## `excludeKeywords` (type: `array`):

Optional. Drop items whose title, summary or categories contain any of these words or phrases (case-insensitive).

## `sinceHours` (type: `integer`):

Optional. Keep only items published (or updated) in the last N hours. Items without a date are dropped when a date filter is used. 0 = no limit.

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

Optional ISO date or date-time, e.g. 2026-11-01 or 2026-11-01T12:00:00Z.

## `onlyNew` (type: `boolean`):

For scheduled alerts: items already returned by a previous run with the same state store, feed and keywords are skipped (and not charged). State is kept in a named key-value store in your account. The first run returns the current items and marks them as seen.

## `stateStoreName` (type: `string`):

Name of the key-value store that remembers seen items. Use a different name per alert/schedule if you want independent memories.

## `autoDiscover` (type: `boolean`):

If a URL is an HTML page, look for <link rel="alternate"> feeds and then common paths (/feed, /rss.xml, /atom.xml, /feed.xml, /index.xml, /rss, /feed.json).

## `maxFeedsPerSite` (type: `integer`):

When a website advertises several feeds, how many to read (comment feeds go last).

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

Add contentHtml with the full HTML that the feed itself publishes (content:encoded, Atom content, JSON content_html). The Actor never downloads the articles.

## `maxSummaryChars` (type: `integer`):

Plain-text summary is cut at this length on a word boundary. 0 = no limit.

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

Feeds fetched in parallel (1–10). robots.txt Crawl-delay is always honored.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://github.blog/"
    },
    {
      "url": "https://www.nasa.gov/news-release/feed/"
    },
    {
      "url": "https://news.ycombinator.com/rss"
    }
  ],
  "maxItemsPerFeed": 50,
  "maxTotalItems": 5000,
  "sinceHours": 0,
  "onlyNew": false,
  "stateStoreName": "rss-feed-reader-state",
  "autoDiscover": true,
  "maxFeedsPerSite": 1,
  "includeContent": false,
  "maxSummaryChars": 500,
  "maxConcurrency": 5
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "startUrls": [
        {
            "url": "https://github.blog/"
        },
        {
            "url": "https://www.nasa.gov/news-release/feed/"
        },
        {
            "url": "https://news.ycombinator.com/rss"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("integriapps/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 = { "startUrls": [
        { "url": "https://github.blog/" },
        { "url": "https://www.nasa.gov/news-release/feed/" },
        { "url": "https://news.ycombinator.com/rss" },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("integriapps/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 '{
  "startUrls": [
    {
      "url": "https://github.blog/"
    },
    {
      "url": "https://www.nasa.gov/news-release/feed/"
    },
    {
      "url": "https://news.ycombinator.com/rss"
    }
  ]
}' |
apify call integriapps/rss-feed-reader --silent --output-dataset

```

## MCP server setup

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