# RSS, Atom & JSON Feed Reader (with feed discovery) (`canopy_ne3/rss-feed-reader`) Actor

Reads the RSS, Atom, RDF and JSON feeds you name into clean rows: title, link, dates, author, text summary, categories and enclosures, optionally full content. Give a feed URL or a page that advertises one. Filter by date. Obeys robots.txt; no proxy, no login.

- **URL**: https://apify.com/canopy_ne3/rss-feed-reader.md
- **Developed by:** [Brenden Bushman](https://apify.com/canopy_ne3) (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 $0.30 / 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 & JSON Feed Reader (with feed discovery)

Turn the feeds you follow into clean, uniform rows you can filter, store, or pass to the next step of an automation.
Give it feed URLs, or ordinary web pages that advertise a feed, and get back one row per item: title, link, published
and updated dates (UTC, ISO 8601), author, a plain-text summary, categories, enclosures (podcast audio, attached
files) and, if you ask, the full content.

RSS 0.9x/1.0/2.0, RDF, Atom and JSON Feed 1.0/1.1 all come out in the same shape. Parsing uses
[feedparser](https://github.com/kurtmckee/feedparser) (BSD licence), which tolerates the malformed feeds found in
the wild, resolves relative links and strips scripts from HTML content. JSON Feed is read directly.

### What you get

- **One row per item**, with the feed's title, link and format on every row, so rows from many feeds can be mixed.
- **Feed discovery**: give a blog's home page and the Actor reads the feeds it advertises with
  `<link rel="alternate">` (up to 5 per page).
- **A date filter** (`publishedAfter`): a date, a date-time, or a period such as `24 hours` or `7 days`. Run it on a
  schedule with `publishedAfter: "1 day"` for a daily digest.
- **A plain-text summary** on every item (HTML removed, at most 2,000 characters), and optionally the full content as
  sanitized HTML and as text (`includeContent`).
- Duplicate URLs are read once.

Failures are reported as rows with `"type": "error"` and are **not charged**: `fetch-failed`, `robots-disallowed`,
`not-a-feed`, `no-feed-found`, `feed-too-large`.

### Respectful by design

- **Only the URLs you list are fetched**, plus the feeds a listed page advertises. Nothing is crawled. The site's
  robots.txt is read first and obeyed, and requests to one site are spaced (500 ms by default). No proxy, no browser,
  no login.
- Only public internet addresses are fetched. A URL or redirect into a private, loopback or link-local network is
  refused.

Read only feeds you are allowed to use, and respect each publisher's terms for what you do with the content.

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `feedUrls` | array | - | Feed URLs, or pages that advertise a feed. Required. |
| `publishedAfter` | string | - | `2026-10-01`, `2026-10-01T08:00:00Z`, `24 hours`, `7 days`, `2 weeks`. Undated items are kept. |
| `maxItemsPerFeed` | integer | `50` | Up to 1,000, in the feed's own order. |
| `includeContent` | boolean | `false` | Adds `contentHtml` and `contentText`. |
| `discoverFeeds` | boolean | `true` | Read the feeds a web page advertises. |
| `requestDelayMs` | integer | `500` | Pause between requests to one site. |

### Output

One dataset row per item, in input order and the feed's own order:

```json
{"type": "item", "requestedUrl": "https://blog.example/", "feedUrl": "https://blog.example/feed.xml",
 "feedTitle": "Example Blog", "feedLink": "https://blog.example/", "feedFormat": "rss20",
 "title": "Spring survey: turbidity fell at all six sites", "link": "https://blog.example/posts/spring-survey",
 "id": "https://blog.example/?p=412", "published": "2026-10-14T09:00:00Z", "updated": null,
 "author": "Field Team", "summary": "All six sampling sites showed lower turbidity than last spring.",
 "categories": ["Surveys"],
 "enclosures": [{"url": "https://blog.example/files/report.pdf", "type": "application/pdf", "length": 2048}]}
```

A failure:

```json
{"type": "error", "requestedUrl": "https://blog.example/about", "feedUrl": "https://blog.example/about",
 "error": {"code": "no-feed-found", "message": "the page is HTML and advertises no RSS, Atom or JSON feed"}}
```

Key-value store record `SUMMARY`: URLs requested, feeds read, items returned, errors, the date cut-off used, and why
the run stopped early if it did.

### Pricing

Pay per event, no start fee, and nothing for failures:

| Event | Price | Per 1,000 |
|---|---|---|
| `feed-read` (one feed fetched and parsed) | $0.001 | $1.00 |
| `item-read` (one item returned) | $0.0003 | $0.30 |

Reading 10 feeds and getting 20 new items from each costs $0.07. Items the date filter drops are not charged. When you
set a maximum charge for a run, the Actor returns the items it covers and stops.

### Limits

- It reads what a feed contains now. Most feeds list only their latest 10-50 items, so for history, run it on a
  schedule.
- Feeds behind a login or a paywall cannot be read: there is no cookie or password field.
- 20 MB per feed at most.

# Actor input Schema

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

Feeds to read (RSS, Atom, RDF or JSON Feed), or web pages that advertise a feed with <link rel="alternate">, which is then read instead. Each URL is fetched once; the site's robots.txt is respected.

## `publishedAfter` (type: `string`):

A date or date-time (2026-10-01, 2026-10-01T08:00:00Z), or a period back from now: '24 hours', '7 days', '2 weeks'. Items without a date are kept. Empty returns every item.

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

Return at most this many items from each feed, in the feed's own order (usually newest first).

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

Add each item's full content as sanitized HTML (contentHtml) and as plain text (contentText), when the feed carries it. The text summary is always included.

## `discoverFeeds` (type: `boolean`):

When a URL is a web page rather than a feed, read the feeds it advertises (up to 5).

## `requestDelayMs` (type: `integer`):

Requests to the same site are spaced by at least this long.

## Actor input object example

```json
{
  "feedUrls": [
    "https://api.apify.com/v2/key-value-stores/uM2zEXblvgf0s1cES/records/feed.xml",
    "https://api.apify.com/v2/key-value-stores/uM2zEXblvgf0s1cES/records/index.html"
  ],
  "maxItemsPerFeed": 50,
  "includeContent": false,
  "discoverFeeds": true,
  "requestDelayMs": 500
}
```

# Actor output Schema

## `results` (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 = {
    "feedUrls": [
        "https://api.apify.com/v2/key-value-stores/uM2zEXblvgf0s1cES/records/feed.xml",
        "https://api.apify.com/v2/key-value-stores/uM2zEXblvgf0s1cES/records/index.html"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("canopy_ne3/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://api.apify.com/v2/key-value-stores/uM2zEXblvgf0s1cES/records/feed.xml",
        "https://api.apify.com/v2/key-value-stores/uM2zEXblvgf0s1cES/records/index.html",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("canopy_ne3/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://api.apify.com/v2/key-value-stores/uM2zEXblvgf0s1cES/records/feed.xml",
    "https://api.apify.com/v2/key-value-stores/uM2zEXblvgf0s1cES/records/index.html"
  ]
}' |
apify call canopy_ne3/rss-feed-reader --silent --output-dataset

```

## MCP server setup

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