# RSS & Atom Feed Reader: Feed Scraper & Monitor, RSS to JSON (`humble-echidna/rss-feed-reader`) Actor

Read and monitor RSS 2.0, RSS 1.0 (RDF), Atom and JSON Feed from feed or website URLs (feeds found automatically). One clean JSON row per item: title, link, UTC dates, author, plain-text and Markdown summary and full text, categories, enclosures. Keyword and date filters, only-new-items mode.

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

## Pricing

from $0.70 / 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

### What does RSS & Atom Feed Reader do?

**RSS & Atom Feed Reader** reads and parses the **RSS, Atom, RDF and JSON feeds** you give it (or a website that
advertises one) and returns **one clean row per item**: title, link, UTC dates, author, summary, full text and media.
Scrape feeds once, or **monitor** them on a schedule. No login, no browser.

[Input fields](https://apify.com/humble-echidna/rss-feed-reader/input-schema) ·
[API](https://apify.com/humble-echidna/rss-feed-reader/api) ·
[Use it from Claude, ChatGPT or Cursor (MCP)](#can-i-use-rss-and-atom-feed-reader-from-an-ai-agent-mcp)

**Jump to:** [Monitor feeds](#monitor-rss-feeds-for-new-items) ·
[Fields](#what-data-does-rss-and-atom-feed-reader-return) · [Price](#how-much-does-it-cost-to-read-rss-feeds) ·
[How to use](#how-to-read-rss-feeds-into-a-dataset) · [Input](#input) ·
[Output](#output) · [AI agents (MCP)](#can-i-use-rss-and-atom-feed-reader-from-an-ai-agent-mcp) ·
[Limits](#limits) · [FAQ](#faq)

**Try it in one click:** the input comes pre-filled with the Rust blog (Atom) and the Django weblog (RSS). That's
about 20 items, or roughly $0.02 (20 × $0.001 per item, plus $0.00005 for the run start). **Then replace them with
the feeds you actually want.**

### Monitor RSS feeds for new items

RSS & Atom Feed Reader can check your feeds on a schedule and give you only the items added since its last run. Set it
up once:

1. **Save a task.** Fill in **Feeds** (and any **Keywords**), turn on **Only new items** (`onlyNewItems: true` in the
   API), then click **Save as a new task** at the top right of the actor's page. The first run returns everything that
   matches; later runs return only items the search hasn't returned before.
2. **Schedule it.** In Apify Console, open **Schedules**, click **Create new**, pick the task and set how often it runs
   (for example every hour, cron `0 * * * *`).
3. **Send the new items where you work,** from the task's **Integrations** tab:
   - **Slack:** a message in the channel you choose when a run succeeds (you pick the events and can edit the
     message).
   - **Email:** *Send results email via Gmail* sends the run's results, with the dataset attached.
   - **Webhook:** a POST to your URL on the `ACTOR.RUN.SUCCEEDED` event. The payload's `resource.defaultDatasetId`
     points to the new items: `GET https://api.apify.com/v2/datasets/<defaultDatasetId>/items?format=json` with your
     API token.
   - **Make, Zapier or n8n:** each has an Apify step that starts on a finished run and reads its dataset.

A run that finds nothing new returns 0 items and costs only the $0.00005 start fee. Slack and email are sent for every
successful run, including a quiet one; to hear only about new items, use the webhook or Make/Zapier/n8n and skip runs
whose dataset is empty. Add the **run failed** event too, so a failed run doesn't go unnoticed. Keep the task's
filters fixed: the memory is per feed and per combination of keywords and "published since", so changing them starts
a fresh search.

### What data does RSS & Atom Feed Reader return?

| Field | Example | Notes |
|---|---|---|
| `title` | `Announcing Rust 1.99.0` | |
| `url` | `https://blog.rust-lang.org/2026/09/18/Rust-1.99.0/` | The item's link, made absolute. |
| `published`, `updated` | `2026-09-18T00:00:00Z` | ISO 8601 UTC; `null` when the feed gives none. |
| `author` | `The Release Team` | A name; email addresses are removed. |
| `summary` | `Both the Steering Council and DSF Board have approved...` | The feed's summary or description, as plain text. |
| `content` | `The Rust team is happy to announce...` | The full text when the feed includes it, else `null`. |
| `summaryMarkdown`, `contentMarkdown` | | With **Also give Markdown** on; otherwise `null`. |
| `categories` | `[]` | As the feed tags the item. |
| `enclosures` | `[{"url", "type", "length"}]` | Attached media: podcast audio, files. |
| `feedTitle`, `feedUrl`, `feedFormat` | `Rust Blog`, `atom` | Which feed the item came from. |
| `id` | `259c5e9aa94ff6342233` | Stable for the same item in the same feed, for deduplication. |

Every item has the same fields; the full record is under [Output](#output).

### How much does it cost to read RSS feeds?

You pay per item returned: **$1.00 per 1,000 items**, plus $0.00005 each time a run starts. A feed that fails,
filtered-out items and items already returned in "only new items" mode are never charged, so a repeat run with nothing
new costs only the start fee.

**It's cheaper on paid Apify plans:** $0.90 per 1,000 items on Starter, $0.80 on Scale and $0.70 on Business. The prices on this page are the Free-plan price, so on a paid plan you pay less than the examples show.

- **The example below:** 20 items × $0.001 = $0.02, plus the $0.00005 start fee; the repeat run $0.00005.
- **A month, for example:** 50 feeds checked every hour with only-new on, about 200 new items a day: 6,000 items ×
  $0.001 = $6.00, plus 720 starts × $0.00005 = $0.036: **about $6.04**.
- **Caps:** **Max results per run** in the input, and **Maximum cost per run** in the run options. It stops cleanly at
  whichever comes first, and stops fetching as soon as the limit is covered, so a capped run is also a fast one.

### How to read RSS feeds into a dataset

1. Open the actor and paste your feed URLs, or website URLs whose page advertises a feed, into **Feeds**, one per line.
2. Optionally add **Keywords** or **Published since** to keep only the items you want.
3. Click **Start**.
4. Open the **Output** tab and export the items as JSON, CSV or Excel, or read them through the API.
5. To follow the feeds, save it as a task and schedule it (see *Monitor RSS feeds for new items* above).

It reads **RSS 2.0** (and the older 0.9x), **RSS 1.0 (RDF)**, **Atom** and **JSON Feed**. When you paste a plain
website or blog URL and the page advertises its feed (`<link rel="alternate">`, as most blogs and news sites do), the
actor finds it and reads it.

### Example: two blogs, then a re-check

The pre-filled input, with **Only new items** turned on:

```json
{"feeds": ["https://blog.rust-lang.org/feed.xml", "https://www.djangoproject.com/rss/weblog/"], "onlyNewItems": true}
```

One of the 20 items (real output from a local run on 2026-09-25; `summary` shortened):

```json
{
  "id": "290a7b371ab7d8551e90",
  "title": "New Technical Governance Approved",
  "url": "https://www.djangoproject.com/weblog/2026/sep/22/new-technical-governance-approved/",
  "published": "2026-09-22T11:00:00Z",
  "updated": null,
  "author": "Tim Schilling and the Steering Council",
  "summary": "Both the Steering Council and DSF Board have approved DEP 19, which implements our new technical governance. ...",
  "content": null,
  "categories": [],
  "enclosures": [],
  "feedTitle": "The Django weblog",
  "feedUrl": "https://www.djangoproject.com/rss/weblog/",
  "feedFormat": "rss"
}
```

The Rust blog's Atom feed carries each post's full text in `content`; the Django feed only a summary. Run again
straight after, the same input returned **0 items**, so only the start fee was charged.

### Ready-to-run examples

Each example opens with the input already filled in. Run it as it is, or change the input first.

- **[Monitor RSS feeds for new posts](https://apify.com/humble-echidna/rss-feed-reader/examples/monitor-rss-feeds-new-posts)**: Read several RSS or Atom feeds at once and get only the items published since the last run, in one clean format.
- **[Track keywords across RSS feeds](https://apify.com/humble-echidna/rss-feed-reader/examples/rss-keyword-alerts)**: Watch RSS feeds for posts that mention your keywords, such as your brand, a competitor or a technology.

### Input

| Field | What it does |
|---|---|
| **Feeds** | Feed URLs, or website URLs whose page advertises a feed, one per line. |
| Keywords | Only items whose title, summary, full text or categories contain one of these words (any case). |
| Published since | Only items published on or after a date (`2026-09-01`), a UTC date and time (`2026-09-01T12:00:00Z`), or a period back from now (`7 days`, `12 hours`, `2 weeks`). |
| Only new items | Only items this search hasn't returned before from the same feed. |
| Also give Markdown | Adds `summaryMarkdown` and `contentMarkdown`. |
| Max results per run | Cap the total number of items across all feeds. |

```json
{
  "feeds": ["https://blog.rust-lang.org/feed.xml", "https://www.djangoproject.com/weblog/"],
  "keywords": ["release", "security"],
  "publishedSince": "7 days",
  "onlyNewItems": true,
  "includeMarkdown": false,
  "maxResults": 100
}
```

### Output

Every item has the same fields. Fields the feed doesn't publish are `null` (or an empty list).

```json
{
  "id": "259c5e9aa94ff6342233",
  "title": "Announcing Rust 1.99.0",
  "url": "https://blog.rust-lang.org/2026/09/18/Rust-1.99.0/",
  "published": "2026-09-18T00:00:00Z",
  "updated": "2026-09-18T00:00:00Z",
  "author": "The Release Team",
  "summary": null,
  "content": "The Rust team is happy to announce a new version of Rust, 1.99.0. ...",
  "summaryMarkdown": null,
  "contentMarkdown": null,
  "categories": [],
  "enclosures": [],
  "guid": "https://blog.rust-lang.org/2026/09/18/Rust-1.99.0/",
  "feedTitle": "Rust Blog",
  "feedUrl": "https://blog.rust-lang.org/feed.xml",
  "feedFormat": "atom",
  "input": "https://blog.rust-lang.org/feed.xml",
  "scrapedAt": "2026-09-24T18:20:59Z"
}
```

- `id` is stable across runs for the same item in the same feed, so you can use it to deduplicate.
- `summary` is the feed's summary or description; `content` is the full text when the feed includes it (RSS
  `content:encoded`, Atom `content`, JSON Feed `content_html`/`content_text`). Many feeds only publish one of the
  two.
- `enclosures` lists attached media as `{"url", "type", "length"}` (length in bytes, when the feed gives it).
- `author` is the name the feed gives. Email addresses are removed; an author given only as an email address
  comes out as `null`.
- Dates are converted to UTC. A date the feed gives without a time zone is taken as UTC.

### Run it on a schedule, or from your own code

- **[Schedule](https://docs.apify.com/platform/schedules):** save the input as a
  [task](https://docs.apify.com/platform/actors/running/tasks) and add it to a schedule, as in
  *Monitor RSS feeds for new items* above.
- **[API](https://apify.com/humble-echidna/rss-feed-reader/api):** fetch a task's latest results with
  `GET https://api.apify.com/v2/actor-tasks/<task id>/runs/last/dataset/items?status=SUCCEEDED&format=csv` and your
  API token (`format` can also be `json` or `xlsx`).
- **[Webhooks](https://docs.apify.com/platform/integrations/webhooks) and automation:**
  a webhook when a run succeeds, or Make, Zapier or n8n through
  [Apify's integrations](https://docs.apify.com/platform/integrations).

#### Can I use RSS & Atom Feed Reader from an AI agent (MCP)?

Yes, through [Apify's MCP server](https://docs.apify.com/platform/integrations/mcp), from Claude, ChatGPT, Cursor or
any other MCP client. Add this to your client's MCP configuration (or let the agent find it with the server's actor
search); your client signs you in to Apify:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=humble-echidna/rss-feed-reader"
    }
  }
}
```

To use an [Apify API token](https://console.apify.com/settings/integrations) instead of signing in, add
`"headers": {"Authorization": "Bearer <APIFY_TOKEN>"}` next to `url`.

The agent passes the same input JSON as above. Have it set **Max results per run** (`maxResults`) or **Published
since** to keep answers small, and **Also give Markdown** when the text goes to an LLM.

### Who it's for

Anyone who follows many feeds and wants new posts as rows in a dataset, a spreadsheet or an automation instead of
a feed-reader app: industry and competitor news tracking, release and security-advisory watching, newsletter
curation, podcast episode lists. Schedule it with **Only new items** and each run returns just the items added since
the last one.

### Why this one?

- **One flat price, no usage bill.** You pay per result at the price above and nothing else: no compute, proxy or storage charges on top, apart from the $0.00005 run-start fee, so you know what a run costs before it starts. Results you don't get aren't charged.
- **Every common feed format, one shape.** RSS, RDF, Atom and JSON Feed all come out with the same fields, dates
  converted to ISO 8601 UTC, relative links made absolute, and HTML turned into readable text.
- **Plain text and Markdown.** Summaries and full text come as clean plain text; switch on "Also give Markdown" to
  get them as Markdown too (headings, lists, links and images kept), ready for an LLM or a RAG pipeline.
- **Monitoring built in.** "Only new items" returns only what a feed added since your last run. Schedule the actor
  and you get a new-post alert for any feed. Keyword and "published since" filters narrow it further.
- **Pay only for items you get.** A feed that fails, filtered-out items and items already returned in
  "only new items" mode are never charged.
- **Polite and safe.** It identifies itself honestly (User-Agent `HumbleEchidnaApify`), follows each site's
  robots.txt (read once per site per run), including opt-outs aimed at AI crawlers such as GPTBot, CCBot or
  ClaudeBot, and Crawl-delay, and only requests public web addresses on the standard
  ports (80 and 443). XML is parsed with entity expansion and external entities switched off.
- **Reliable.** One failing feed never affects the others in your run. The run log and the `RUN_STATS`
  record say exactly which feed had a problem and why.

### Limits

- **Items without a date are kept** by "Published since", because the feed doesn't say they're old.
- **"Only new items" is remembered per search**: per feed and per combination of keywords and "published since".
  Two scheduled searches on the same feed never hide each other's items. An item counts as returned only once it
  is actually in your dataset, so items cut off by your result or cost limit come back on the next run, and a feed
  that fails to load forgets nothing. The memory lives in a key-value store named `rss-feed-reader-seen` in your
  own Apify account; delete it to start over.
- **The same feed given twice** (say, as a website and as its feed URL) is read and charged once.
- **Sizes:** a feed (or the page that advertises it) can be up to 10 MB, and up to 5,000 items are read per
  feed. Each text field is cut at 100,000 characters; the item's link has the rest.
- When a website advertises several feeds, the first one is read (comment feeds last). To read a different one,
  paste its URL.

### FAQ

#### Why does a feed that used to work now fail or return fewer items?

The site may have moved or changed its feed
without notice. The run log names the feed and what went wrong, and every other feed in the run is unaffected.
Please open an issue with the input you used.

#### Why does it say the page doesn't advertise a feed?

Not every site has one, and some only link it visibly instead of
advertising it in the page head. Find the feed's own URL (often `/feed`, `/rss` or `/atom.xml`) and paste that.

#### Why does it say robots.txt disallows the URL?

The site asked automated clients not to fetch it, and this actor
respects that. That includes sites that only opt out of AI crawlers (GPTBot, CCBot, ClaudeBot and similar): since
this actor's output is often used for AI, it honours those opt-outs too.

#### Can I get the full article when a feed only has a summary?

Not from the feed itself. [Article Extractor](https://apify.com/humble-echidna/article-extractor) opens each article
and returns its full text, author and date (see Related actors).

#### Is it legal to read RSS feeds with it?

It reads feeds that site owners publish on purpose for feed readers and other software, from
the URLs you give it. It uses no login and doesn't get around any access control. Feed content stays its
publisher's: check each feed's terms before you republish what you collect.

### Related actors

| Actor | Use it when |
|---|---|
| [Article Extractor](https://apify.com/humble-echidna/article-extractor) | A feed gives only a summary (like the Django feed above): it opens each article and returns the full text, author and date. It finds feeds itself and has its own only-new mode, so for full articles you can use it on its own. |
| [Audio & Video Transcriber](https://apify.com/humble-echidna/audio-transcriber) | You want podcast feeds' episodes as transcripts and captions. |
| [Website & Page to Markdown for RAG and LLMs](https://apify.com/humble-echidna/page-to-markdown) | You want linked pages that aren't articles, as Markdown for an LLM. |

### Feedback and support

Found a bug, or need a field or feed format that isn't here? Open an issue on the **Issues** tab with the input you
used.

### Versions

Current version: **1.0**. See the Changelog tab for what changed in each version.

# Changelog

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

# Actor input Schema

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

Feed URLs (RSS 2.0, RSS 1.0/RDF, Atom or JSON Feed), one per line, e.g. https://blog.rust-lang.org/feed.xml. A website or page URL works too if the page advertises its feed (<link rel="alternate">), e.g. https://www.djangoproject.com/weblog/. Only public http/https addresses on the standard ports (80, 443).

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

Only return items whose title, summary, full text or categories contain at least one of these words or phrases (case-insensitive), one per line, e.g. security or "release notes". Leave empty (the default) for every item.

## `publishedSince` (type: `string`):

Only return items published on or after this point: a date (2026-09-01), a date and time in UTC (2026-09-01T12:00:00Z), or a period back from now ('7 days', '12 hours', '2 weeks'). Items the feed gives no date for are kept. Leave empty (the default) for no date limit.

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

Default false. When true, return only items this search hasn't returned before from the same feed (remembered in your Apify account, per feed and per keyword/date filter). The first run returns everything that matches. Good for scheduled monitoring.

## `includeMarkdown` (type: `boolean`):

Default false. When true, besides plain text, also return the summary and the full text as Markdown (headings, lists, links and images kept), e.g. for LLM or RAG pipelines. Makes each result larger.

## `maxResults` (type: `integer`):

Stop after this many items in total across all feeds, e.g. 20. Minimum 1; leave empty (the default) for no limit. The run also stops cleanly at the maximum cost per run you set in the run options, whichever comes first. Set it to keep a run small and quick.

## Actor input object example

```json
{
  "feeds": [
    "https://blog.rust-lang.org/feed.xml",
    "https://www.djangoproject.com/rss/weblog/"
  ],
  "onlyNewItems": false,
  "includeMarkdown": false
}
```

# Actor output Schema

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

No description

## `runStats` (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 = {
    "feeds": [
        "https://blog.rust-lang.org/feed.xml",
        "https://www.djangoproject.com/rss/weblog/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("humble-echidna/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 = { "feeds": [
        "https://blog.rust-lang.org/feed.xml",
        "https://www.djangoproject.com/rss/weblog/",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("humble-echidna/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 '{
  "feeds": [
    "https://blog.rust-lang.org/feed.xml",
    "https://www.djangoproject.com/rss/weblog/"
  ]
}' |
apify call humble-echidna/rss-feed-reader --silent --output-dataset

```

## MCP server setup

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