# RSS Feed Reader: Atom & RSS to JSON with Feed Finder (`private_image_hg9/rss-feed-reader-finder`) Actor

Read RSS, Atom and JSON Feed entries as clean JSON: title, link, dates in UTC, author, plain-text summary, categories, podcast enclosures and images. Give feed addresses or plain websites; it finds a site's feed for you. Pay only per entry saved.

- **URL**: https://apify.com/private_image_hg9/rss-feed-reader-finder.md
- **Developed by:** [Michael Shanker](https://apify.com/private_image_hg9) (community)
- **Categories:** News, Developer tools, 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 entries

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 Feed Reader: Atom & RSS to JSON with Feed Finder

Give it feed addresses, or just website addresses, and get back **every entry as a clean JSON row**: title, link, publish and update dates in UTC, author, a plain-text summary, categories, podcast audio files, and an image when the feed has one.

Don't know where a site's feed is? Give the website (`xkcd.com`, `https://blog.example.com/`) and it **finds the feed for you**.

**You pay per entry saved: $0.50 per 1,000 entries.** No start fee. Inputs with no feed, a broken feed, or a site that asks tools to stay away still get a free row saying why.

### Who it's for

- **News and content monitoring:** follow publications, government press releases, competitors' blogs or changelogs, and send new entries to Google Sheets, Slack, Zapier, Make or n8n.
- **Podcast catalogs:** episode titles, dates, durations and audio file links with size and type.
- **Developers:** one consistent JSON shape for RSS 0.9x, 1.0, 2.0, Atom and JSON Feed, so your code doesn't have to care which format a site uses.
- **AI and research pipelines:** clean plain text (no HTML) ready for summarizing, tagging or search.

### What it does

- **Reads every common format:** RSS 0.90 to 2.0, RSS 1.0 (RDF), Atom 0.3 and 1.0, and JSON Feed 1.0 and 1.1.
- **Finds feeds from a website address.** It reads the page and follows the feeds it advertises (`<link rel="alternate" type="application/rss+xml">`, Atom and JSON Feed too), skipping comment feeds unless that's all there is. If the page advertises none, it tries the usual addresses in order: `/feed`, `/rss`, `/rss.xml`, `/atom.xml`, `/feed.xml`, `/index.xml`, then `/feeds/posts/default` (Blogger) and `/?feed=rss2` (WordPress), and stops at the first real feed. HTML "page not found" pages at those addresses are recognized and skipped.
- **Clean, consistent fields:** dates converted to ISO 8601 UTC (`2026-11-02T09:00:00Z`), links made absolute, HTML stripped from titles and summaries, entities decoded (even double-escaped ones like `&amp;amp;`), author names without email addresses.
- **Copes with messy feeds:** wrong or missing character encodings (windows-1252, Latin-1), bare `&` characters, HTML entities XML doesn't know, gzip compression, and feeds served with the wrong content type. A feed that can only be read in tolerant mode says so.
- **Filters before you pay:** newest N entries per feed, only entries published after a date or within the last N days, and repeated entries across your feeds removed. Entries left out are not charged.

### Compared with other Store feed readers

Prices from the Apify Store listings on 4 November 2026. Check the current listings before you compare.

| | This tool | Most-used Store RSS reader | Other Store RSS readers |
|---|---|---|---|
| Price per entry | $0.0005 | $0.002 | $0.008, or a $0.035 start fee per run |
| Start fee | None | $0.001 per run | Varies |
| 10,000 entries in one run | $5 | About $20 | About $80 at $0.008 per entry |
| Inputs that fail (no feed, broken, blocked) | Free row with the reason | See its listing | See its listing |

What this tool adds, whatever you compare it with: a feed finder for plain website addresses, JSON Feed support, podcast enclosures with type and size, dates normalized to UTC, plain-text summaries, and repeats across feeds removed before you're charged.

### Input

| Field | What it does |
|---|---|
| **Feeds or websites** | One per line: a feed (`https://hnrss.org/frontpage`, `feed://...` works too) or a website or page (`xkcd.com`, `https://wordpress.org/news/`). A bare domain tries https, then https://www., then http. |
| **Max entries per feed** | The newest entries of each feed, up to this many (default 50, max 10,000). |
| **Published on or after** | A date (`2026-10-01`) or a relative time (`7 days`). Entries with no date at all are left out when set. |
| **Only the last N days** | The same as a relative date, as a number (0 = off). |
| **Remove repeated entries** | On by default: an entry that shows up in several of your feeds (matched by guid/id, or by link when there is none) is saved and charged once. |
| **Max summary length** | Plain-text summary cut at a word boundary (default 1,000 characters, 0 = no limit). |
| **Full content as text** | Also save the full post text when the feed carries it (up to 50,000 characters). |
| **Feed details row** | Add one free row per feed with its title, site link, description, language, image, generator and counts. |
| **Feeds at once** | Parallel inputs (default 10). Each host still gets at most one request per second. |

Example input:

```json
{
  "startUrls": ["https://hnrss.org/frontpage", "xkcd.com", "https://feeds.npr.org/510289/podcast.xml"],
  "maxItemsPerFeed": 20,
  "publishedAfter": "7 days",
  "includeFeedInfo": true
}
```

### Output

One row per entry (values illustrative):

```json
{
  "rowType": "item",
  "status": "ok",
  "title": "Episode 312: The price of eggs",
  "link": "https://www.example-podcast.org/episodes/312",
  "guid": "ep-312",
  "published": "2026-11-03T05:00:00Z",
  "updated": null,
  "author": "Jane Doe",
  "summary": "Why egg prices went up, and why they came back down.",
  "content": null,
  "categories": ["Economics"],
  "enclosures": [{"url": "https://media.example-podcast.org/312.mp3", "type": "audio/mpeg", "length": 32345678}],
  "image": "https://www.example-podcast.org/art/312.jpg",
  "duration": "00:42:10",
  "feedTitle": "Example Podcast",
  "feedUrl": "https://www.example-podcast.org/feed.xml",
  "siteLink": "https://www.example-podcast.org/",
  "feedType": "RSS 2.0",
  "input": "example-podcast.org",
  "error": null,
  "fetchedAt": "2026-11-04T16:57:22Z"
}
```

`rowType` is `item` for an entry (the only charged row), `feed` for a feed details row, and `status` for an input with nothing to read. Status rows have `status` set to one of:

- `feed_not_found`: the address gave a 404, or the website advertises no readable feed and none of the usual addresses is a feed.
- `parse_error`: something that says it is a feed but can't be read.
- `empty_feed` / `no_matching_items`: the feed was read but has no entries, or none passed your date filter or were new.
- `duplicate_feed`: another input already led to the same feed.
- `blocked_by_robots`: the site's robots.txt asks this tool not to read that address.
- `unreachable`: the site is down, refused, or answered with an error (`error` says which).
- `invalid_input`: not a usable public web address.

The run also saves a `SUMMARY` record: counts per status, entries saved and charged, repeats and older entries skipped, and one line per input saying which feed was read and how it was found.

### Pricing

Pay per event: **$0.0005 per entry saved ($0.50 per 1,000)**. No start fee and nothing for failed inputs, feed details rows, repeated entries or entries your filters leave out. Set a maximum charge per run in the run options and the Actor stops cleanly when it's reached.

### Good to know

- **Only what the feed publishes.** Many feeds carry the newest 10 to 50 entries only; older posts aren't in the feed and can't be read from it. For a full archive, use a sitemap or crawler tool.
- **Polite reading.** It names itself in its User-Agent (`RssFeedReaderBot`), waits at least a second between requests to the same host (longer if robots.txt asks), and **obeys robots.txt for every request, feed addresses included**: if a site's robots.txt disallows a feed for this tool or for all bots, the feed isn't read and you get a free `blocked_by_robots` row.
- **Up to 5 MB per feed.** Larger feeds (some podcasts with long histories) are cut at 5 MB; the entries before the cut are kept, which in most feeds are the newest. The `SUMMARY` marks such feeds.
- **Public feeds only.** No logins or paywalled feeds, and local or private network addresses are never fetched.
- Sites that block automated visitors (some answer `HTTP 403`) can't be read.

This Actor isn't affiliated with or endorsed by any of the sites whose feeds it reads. The content of each feed belongs to its publisher; check their terms before you republish it.

### More tools from the same developer

- [News Scraper: GDELT Articles, Full Text & 65 Languages](https://apify.com/private_image_hg9/news-search-gdelt)
- [Hacker News Scraper: Search, Stories & Comments](https://apify.com/private_image_hg9/hacker-news-scraper)
- [Google Trends Scraper: Interest Over Time, Regions & Queries](https://apify.com/private_image_hg9/google-trends-scraper)
- [OpenAlex Papers Search: Scholarly Works, Citations & Abstracts](https://apify.com/private_image_hg9/openalex-papers-search)
- [ClinicalTrials.gov Search: Studies, Phases, Sponsors & Status](https://apify.com/private_image_hg9/clinical-trials-search)
- [Federal Contracts Search: SAM.gov Opportunities & Award History](https://apify.com/private_image_hg9/federal-contracts-search)

# Actor input Schema

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

One per line. A feed address (RSS, Atom or JSON Feed) like https://hnrss.org/frontpage is read directly. A website or page like xkcd.com or https://blog.example.com/ is searched for its feed: the feeds its HTML advertises first, then the usual addresses (/feed, /rss, /rss.xml, /atom.xml, /feed.xml, /index.xml, /feeds/posts/default, /?feed=rss2). Repeats are read once.

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

The newest entries of each feed are saved, up to this many. Each saved entry is one charged row.

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

Keep only entries published (or, without a publish date, updated) on or after this date, like 2026-10-01, or within a relative time like 7 days. Entries without any date are left out when this is set.

## `maxAgeDays` (type: `integer`):

Keep only entries from the last N days (0 = no limit). Same as a relative date above; if both are set, the later cut-off wins.

## `dedupeItems` (type: `boolean`):

Save an entry once even if it appears in several of your feeds (or twice in one feed). Entries are matched by their guid/id, or by link when they have none. Repeats are not charged.

## `summaryMaxLength` (type: `integer`):

The summary (description) is saved as plain text, HTML removed, cut at a word boundary at this length. 0 = no limit.

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

Also save the full post text when the feed includes it (content:encoded in RSS, content in Atom and JSON Feed), as plain text up to 50,000 characters.

## `includeFeedInfo` (type: `boolean`):

Add one free row per feed with its title, site link, description, language, image, generator, type, how it was found, and how many entries it had and were saved.

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

How many inputs are read in parallel. Each host still gets at most one request per second (longer if its robots.txt asks).

## Actor input object example

```json
{
  "startUrls": [
    "https://hnrss.org/frontpage",
    "xkcd.com"
  ],
  "maxItemsPerFeed": 20,
  "maxAgeDays": 0,
  "dedupeItems": true,
  "summaryMaxLength": 1000,
  "includeContent": false,
  "includeFeedInfo": false,
  "maxConcurrency": 10
}
```

# Actor output Schema

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

One row per feed entry, plus one free row for each input that had nothing to read (and a feed details row per feed if you asked for it).

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

Counts for the run and one entry per input: which feed was read, how it was found, entries saved and skipped, and whether the spending cap was reached.

# 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": [
        "https://hnrss.org/frontpage",
        "xkcd.com"
    ],
    "maxItemsPerFeed": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("private_image_hg9/rss-feed-reader-finder").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": [
        "https://hnrss.org/frontpage",
        "xkcd.com",
    ],
    "maxItemsPerFeed": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("private_image_hg9/rss-feed-reader-finder").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": [
    "https://hnrss.org/frontpage",
    "xkcd.com"
  ],
  "maxItemsPerFeed": 20
}' |
apify call private_image_hg9/rss-feed-reader-finder --silent --output-dataset

```

## MCP server setup

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

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/4kaKLm38y3IGfLD63/builds/2MucGOyc4UN6TERmR/openapi.json
