# RSS Feed Reader & Scraper: Atom, JSON Feed & New-Item Monitor (`jtpalms/rss-feed-monitor`) Actor

RSS feed reader and scraper. Read any RSS, Atom or JSON Feed, or give a website and it finds the feed. Clean items with dates, authors, summaries, images and podcast enclosures. Schedule it with "Only new items" to get only what you have not seen before. USD 1.50 per 1,000 items.

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

## Pricing

from $1.20 / 1,000 feed items

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?

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 & Scraper: RSS, Atom and JSON Feed New-Item Monitor

Give it feed URLs or plain website URLs and get back clean, consistent items: title, link, author, publish date, plain-text summary, categories, image and podcast audio. It reads RSS 2.0, RSS 1.0 (RDF), Atom and JSON Feed, and finds the feed for you when you give it a website.

Turn on **Only new items** and schedule it: every run returns only the items that were not there last time. Runs with nothing new return nothing and cost nothing.

**USD 1.50 per 1,000 items.** Feeds that fail are reported free.

### What people use it for

- **News and competitor monitoring.** Watch competitor blogs, press rooms, changelogs, Google News searches and industry news. Schedule it hourly with **Only new items** and send the new items to Slack, Google Sheets, email or a webhook.
- **Keyword alerts.** Add **Keywords** such as `acquisition`, `your brand`, `startup*` and get only the matching new stories.
- **Podcast episode tracking.** Get each new episode with its audio URL, file size, duration and cover image. Good for show-notes pipelines, transcription and archiving.
- **Release tracking.** Follow GitHub releases (`https://github.com/owner/repo/releases.atom`) and product changelogs.
- **Content aggregation.** Merge many feeds into one dataset with the same fields for every source, newest first, for a newsletter, a news page or a dashboard.
- **AI and RAG ingestion.** Turn on **Include full text** to get the article text without HTML (up to 10,000 characters) and feed only new documents into your vector store or LLM workflow.

### Sample output

Real items, trimmed:

```json
{
  "feedUrl": "https://wordpress.org/news/feed/",
  "feedTitle": "WordPress News",
  "siteUrl": "https://wordpress.org/news",
  "feedFormat": "RSS 2.0",
  "itemId": "https://wordpress.org/news/?p=21731",
  "title": "WordPress 7.1.2 Release",
  "link": "https://wordpress.org/news/2026/09/wordpress-7-1-2-release/",
  "author": "John Blackbourn",
  "publishedAt": "2026-09-22T14:01:20.000Z",
  "updatedAt": null,
  "summaryText": "This security release features a fix for a critical severity security vulnerability. Because this is a security release, it is recommended that you update your sites immediately...",
  "categories": ["Releases", "Security"],
  "enclosure": null,
  "imageUrl": null,
  "scrapedAt": "2026-09-28T18:48:17.759Z"
}
```

A podcast episode:

```json
{
  "feedUrl": "https://feeds.npr.org/510289/podcast.xml",
  "feedTitle": "Planet Money",
  "siteUrl": "https://www.npr.org/podcasts/510289/planet-money",
  "feedFormat": "RSS 2.0",
  "itemId": "10652924-571e-4b6e-bd4f-11f819c1dc21",
  "title": "Middlegarchs are the new Oligarchs",
  "link": "https://www.npr.org/2026/09/25/nx-s1-5981194/stealthy-wealthy-everywhere-millionaires-pass-through",
  "publishedAt": "2026-09-25T21:46:44.000Z",
  "summaryText": "Wanna know who is really in the top 1%? And how they use their influence? It may not be who you think...",
  "enclosure": {
    "url": "https://tracking.swap.fm/track/XvDEoI11TR00olTUO8US/.../audio/128/default.mp3?...",
    "type": "audio/mpeg",
    "length": 29504661,
    "duration": 1843
  },
  "imageUrl": "https://npr.brightspotcdn.com/dims3/default/strip/false/crop/3000x3000+0+0/resize/3000/..."
}
```

| Field | What it is |
|---|---|
| `feedUrl`, `feedTitle`, `siteUrl`, `feedFormat` | The feed the item came from. For a website input, `feedUrl` is the feed that was found. |
| `itemId` | The item's guid or id, else its link. This is what "Only new items" remembers. |
| `title`, `link`, `author` | Cleaned text. Relative links are made absolute. E-mail addresses are removed from authors. |
| `publishedAt`, `updatedAt` | ISO 8601 in UTC, parsed from RFC 822, ISO 8601 and the odd formats real feeds use. |
| `summaryText` | The description or summary with HTML removed, up to 1,000 characters. |
| `contentText` | Only with **Include full text**: the full text the feed provides, HTML removed, up to 10,000 characters. |
| `categories` | Categories, tags or subjects. |
| `enclosure` | `url`, `type`, `length` (bytes) and `duration` (seconds) for podcast audio, video or other attachments. |
| `imageUrl` | The item's image: media thumbnail, iTunes image, image enclosure, or the first real image in the content. |
| `scrapedAt` | When the run read the feed. |

### How to use it

1. Add feed URLs or website URLs to **Feeds or websites**, one per line. `bbc.co.uk/news` works as well as `https://feeds.bbci.co.uk/news/rss.xml`.
2. Optionally narrow it down:
   - **Keywords**: `AI`, `electric vehicle`, `startup*`, or `/gpt-?\d/` for a regular expression.
   - **Published within (days)**: `7`.
   - **Max items per feed**: `100` by default, newest first.
3. Click **Start** and export the results as JSON, CSV or Excel, or read them through the Apify API.

#### Set it up as a monitor

1. Turn on **Only new items**.
2. Pick what the first run does: **All current items** gives you what is in the feeds today; **None, just set the starting point** outputs nothing and records the current items, so you only get what is published from now on.
3. Save it as a task and add a **schedule** (for example every hour, or every morning at 8).
4. In the task's **Integrations** tab, connect Slack, Google Sheets, Zapier, Make or a webhook, so each run's new items land where you work.

Tip: a schedule every 15 to 60 minutes is plenty for news; daily is fine for blogs, podcasts and releases. The actor sends conditional requests (ETag and Last-Modified), so a feed that has not changed answers "not modified" without sending the whole file again. Runs stay fast and polite.

If you watch the same feeds from two schedules with different keywords, give each one its own **Monitor name** (under Advanced) so they keep separate memories.

### Pricing

| What | Price |
|---|---|
| Feed item in the results | USD 0.0015 (USD 1.50 per 1,000) |
| Feed that fails (not found, not a feed, blocked) | Free |
| Monitor run where nothing is new | Free |

Examples: 20 news feeds with about 10 new items an hour, checked hourly, is about 4,800 items a day, USD 7.20. Ten podcasts checked daily is a few items a week, a few cents a month.

Set a maximum cost per run in the run options. The actor stops cleanly when it gets there, and with **Only new items** the items it did not save are kept for the next run.

### What it handles

- RSS 0.9x and 2.0, RSS 1.0 (RDF), Atom 1.0 and 0.3, JSON Feed 1.0 and 1.1.
- Feed discovery from a website: `<link rel="alternate">` tags first (skipping comment feeds), then `/feed`, `/rss`, `/rss.xml`, `/atom.xml`, `/feed.xml` and `/index.xml`, next to the page and at the site root. With **Only new items** on, the feed it finds is remembered for later runs.
- gzip and compressed responses, redirects, `feed://` URLs, CDATA, HTML entities (including the ones that are not valid XML, like `&nbsp;` and `&rsquo;`), double-escaped titles, `xml:base` and relative links, Latin-1, Windows-1252, Shift_JIS and other charsets.
- Media RSS (`media:content`, `media:thumbnail`, `media:group`), iTunes podcast tags, Dublin Core (`dc:creator`, `dc:date`, `dc:subject`), FeedBurner original links, YouTube channel feeds.
- Broken feeds: junk before the XML, an unclosed tag in one item or a cut-off download. Every item that can be read is kept.
- Duplicate items and duplicate inputs, counted once.

### Limits

- **The actor identifies itself.** Every request carries the user agent `Mozilla/5.0 (compatible; rss-feed-monitor/1.0; +https://apify.com/JTPalms/rss-feed-monitor)`, with plain request headers. It never pretends to be a browser. Some sites block bots; a blocked request is reported as an error, not hidden.
- A feed only holds what the publisher puts in it: usually the latest 10 to 50 items, sometimes only a short summary. Older items are not in the feed.
- **Only new items** remembers the latest 5,000 item IDs per feed, in the `rss-feed-monitor` key-value store in your account. If a publisher changes an item's guid, it counts as new.
- On later runs, new items beyond **Max items per feed** are kept for the next run rather than dropped.
- **Published within (days)** leaves out items that have no date.
- Feeds behind a login are not supported (you get "HTTP 401"). Some sites, Reddit for example, block automated requests and answer HTTP 403 or 429; this actor does not get around such blocks.
- Feeds larger than 50 MB are cut at 50 MB.

### Related actors

- [Sitemap URL Extractor: All Pages of Any Website](https://apify.com/JTPalms/sitemap-url-extractor): Get every URL of a website from its XML sitemaps.
- [Hacker News Scraper: Stories, Comments, Search & Alerts](https://apify.com/JTPalms/hacker-news): Hacker News front page, new, best, Ask HN, Show HN and job lists, or keyword search with date, points and comment filters.
- [Bluesky Posts Scraper: Accounts, Threads, Feeds & Alerts](https://apify.com/JTPalms/bluesky-posts): Public Bluesky posts without a login: the latest posts of any accounts, whole reply threads, and third-party custom feeds.
- [Government Tenders Monitor: Canada, UK & EU Bid Alerts](https://apify.com/JTPalms/gov-tenders-monitor): New public tenders from official open data in one clean feed: CanadaBuys (federal Canada), UK Find a Tender, EU TED, and US SAM.gov with...

### FAQ

**Is it legal?** Feeds are published so that other programs can read and syndicate them; that is what RSS and Atom are for. The actor only reads public feed files and, for discovery, the public page you give it. It does not log in, and it does not collect personal data: e-mail addresses are stripped from author fields. Respect each publisher's terms when you republish their content.

**How does "Only new items" know what is new?** Each item's guid (or id, or link) is stored per feed after the run. The next run outputs only items whose ID is not stored. Items your keyword or date filters rejected are also remembered, so they are never billed later.

**Why did the first monitor run return items?** With **All current items** the first run returns what the feed has today. Choose **None, just set the starting point** to get only items published after the first run.

**Can I start over?** Yes. Delete the matching records in the `rss-feed-monitor` key-value store (Storage, Key-value stores), or use a new **Monitor name**.

**Can I monitor a Google News search?** Yes. Use a Google News RSS URL such as `https://news.google.com/rss/search?q=your+topic&hl=en-US&gl=US&ceid=US:en`.

**A site says "No feed found".** The site does not publish a feed at any of the usual places. Look for an RSS or Atom icon on the site and paste that URL directly.

**Something missing or wrong?** Open an issue with the feed URL.

# Actor input Schema

## `feeds` (type: `array`):

Feed URLs (RSS, Atom or JSON Feed) or plain website URLs, one per line. For a website the actor finds the feed itself: first from the page's <link rel="alternate"> tag, then at /feed, /rss, /rss.xml, /atom.xml, /feed.xml and /index.xml. Duplicates are removed.

## `onlyNewItems` (type: `boolean`):

Remember which items each feed has shown and output only items that were not seen in earlier runs. Schedule the actor (hourly, daily) to use this as a monitor: runs with nothing new output nothing and cost nothing. The memory is kept in your "rss-feed-monitor" key-value store (the latest 5,000 item IDs per feed).

## `firstRunOutput` (type: `string`):

What the first run for a feed outputs. All: the items currently in the feed (up to the maximum per feed). None: nothing, it only records what is there now, so you get only items published after today.

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

At most this many items per feed per run, newest first. 0 means no limit. With "Only new items", new items beyond this limit are kept for the next run.

## `publishedWithinDays` (type: `integer`):

Optional. Only items published in the last N days. Items without any date are left out when this is set.

## `keywords` (type: `array`):

Optional. Keep only items whose title or summary contains at least one of these. Whole words, not case-sensitive: "AI" does not match "said". End a word with \* for any ending ("startup\*"), or write /pattern/ for a regular expression.

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

Add contentText: the item's full text as the feed provides it, HTML removed, up to 10,000 characters. Handy for AI and search indexing. Many feeds carry only a summary.

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

How many feeds to read at the same time.

## `monitorId` (type: `string`):

Optional. Keeps a separate memory of seen items. Use a different name for each schedule that watches the same feeds with different keywords, so they do not share what counts as new.

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

Optional. Only needed if a site blocks requests from data centers (HTTP 403 or 429 errors).

## Actor input object example

```json
{
  "feeds": [
    "https://feeds.bbci.co.uk/news/world/rss.xml",
    "https://github.com/nodejs/node/releases.atom",
    "https://www.jsonfeed.org/feed.json",
    "https://blog.cloudflare.com"
  ],
  "onlyNewItems": false,
  "firstRunOutput": "all",
  "maxItemsPerFeed": 100,
  "includeContent": false,
  "maxConcurrency": 10
}
```

# Actor output Schema

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

All output rows in the default dataset (JSON, CSV, Excel via the format parameter).

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

Counts and per-input status for this run.

# 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 = {
    "feeds": [
        "https://feeds.bbci.co.uk/news/world/rss.xml",
        "https://github.com/nodejs/node/releases.atom",
        "https://www.jsonfeed.org/feed.json",
        "https://blog.cloudflare.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("jtpalms/rss-feed-monitor").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 = { "feeds": [
        "https://feeds.bbci.co.uk/news/world/rss.xml",
        "https://github.com/nodejs/node/releases.atom",
        "https://www.jsonfeed.org/feed.json",
        "https://blog.cloudflare.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("jtpalms/rss-feed-monitor").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 '{
  "feeds": [
    "https://feeds.bbci.co.uk/news/world/rss.xml",
    "https://github.com/nodejs/node/releases.atom",
    "https://www.jsonfeed.org/feed.json",
    "https://blog.cloudflare.com"
  ]
}' |
apify call jtpalms/rss-feed-monitor --silent --output-dataset

```

## MCP server setup

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

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/I62tEFzsXokuNrGoq/builds/p7h4hcs8UDQ5ipYbp/openapi.json
