# RSS/Atom/JSON Feed Reader — $0.0005/item (`plainapi/rss-atom-json-feed-reader-for-llm`) Actor

You pay only for items actually returned. Nothing found, nothing charged. Read RSS, Atom and JSON feeds into clean plain text, ready to hand to a model. Give it a site URL and the feed is found for you. Honours robots.txt, no browser, no key.

- **URL**: https://apify.com/plainapi/rss-atom-json-feed-reader-for-llm.md
- **Developed by:** [Shun Furu](https://apify.com/plainapi) (community)
- **Categories:** News, AI, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 items

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## RSS Feed Reader — Atom and JSON Feed to clean text

Read RSS, Atom and JSON feeds into flat rows of **plain text**, ready to hand to a model or drop
into a database.

Give it a feed URL, or just a site URL and the feed will be found for you.

```
Input:   ["https://news.ycombinator.com/rss", "https://blog.rust-lang.org"]
Output:  one row per item — title, author, date, summary, full text, tags, URL
```

### Why this one

Feeds are the one part of the web published specifically so machines can read them, which makes
them the cleanest possible source: no blocking, no bot protection, nothing to work around.

What is usually missing is everything after fetching:

- **Three formats, one shape.** RSS, Atom and JSON Feed all come back as identical rows, so a
  mixed list of sources needs no per-source handling.
- **Markup removed.** Feed bodies are HTML wrapped in XML wrapped in entities. This returns plain
  text, which is what you want when the next step is a model or a search index.
- **Dates normalised.** RFC 822, RFC 3339 and the various things feeds do in practice all come out
  as ISO 8601.
- **Feed discovery.** Pass `https://blog.rust-lang.org` and the feed at `/feed` is found — the same
  way a browser does it, by reading the page's `<link rel="alternate">` tags. `robots.txt` is
  checked first.
- **Malformed feeds still parse.** Real feeds break XML rules more often than not, so the parser
  is deliberately forgiving rather than strict.

### Input

Every field is optional. Run it with the defaults and it works.

| Field | Type | Default | What it does |
|---|---|---|---|
| `feeds` | array of strings | two example feeds | Feed URLs, or site URLs to discover feeds from |
| `keyword` | string | — | Keep only items matching any of these words (title, summary, content, tags) |
| `since` | string | — | ISO date. Drop items published before it. Items with no date are kept |
| `includeContent` | boolean | `true` | Include the full item body. Turn off for a lighter, cheaper result |
| `maxItemsPerFeed` | integer | `0` (no limit) | Cap items per feed |

#### Examples

Everything on the front page of Hacker News, as text:

```json
{ "feeds": ["https://news.ycombinator.com/rss"] }
```

Recent posts about Rust from several engineering blogs, found from their homepages:

```json
{
  "feeds": ["https://blog.rust-lang.org", "https://github.blog", "https://blog.cloudflare.com"],
  "keyword": "rust",
  "since": "2026-08-01"
}
```

Titles and links only, for a lightweight daily digest:

```json
{
  "feeds": ["https://news.ycombinator.com/rss"],
  "includeContent": false,
  "maxItemsPerFeed": 20
}
```

### Output

| Field | Type | Description |
|---|---|---|
| `feedUrl` | string | The feed that was read — useful when it was discovered rather than given |
| `feedTitle` | string | Feed title |
| `feedFormat` | string | `rss` | `atom` | `jsonfeed` |
| `siteUrl` | string | The site the feed belongs to |
| `id` | string | The item's own identifier, or its URL |
| `title` | string | Item title |
| `url` | string | Link to the item |
| `author` | string | Where the feed publishes one |
| `publishedAt` | string | null | ISO 8601 |
| `updatedAt` | string | null | ISO 8601 |
| `summary` | string | Plain text |
| `content` | string | Full body as plain text, when `includeContent` is on |
| `tags` | array | Categories the feed assigns |
| `fetchedAt` | string | When the row was produced |

A `SUMMARY` record is written to the key-value store: which feed each source resolved to, its
format, and how many items matched your filters.

### Pricing

| | Price |
|---|---|
| Starting a run | **$0.00001** — one US cent per 1,000 runs |
| Each item returned | **$0.0005** — 50 US cents per 1,000 items |

A source with no feed produces no rows, and errors go to the log and `SUMMARY` rather than the
dataset — so a run that finds nothing costs nothing.

### Typical uses

- **Feeding a model.** Plain text, no markup, one shape across sources.
- **Monitoring.** Watch a list of blogs or release feeds for a keyword.
- **Digests and newsletters.** Pull the day's items and format them downstream.
- **Archiving.** Keep a structured record of what a source published and when.

### Notes on data and compliance

- Feeds are published for machine consumption; nothing here is scraped around a restriction.
- `robots.txt` is checked before fetching any page that is not already a feed.
- No personal data is collected beyond an author name where a feed publishes one.
- The Actor backs off on `429` and does not retry `404`.

### Limitations — stated up front

- Only the feed's own content is returned. If a feed publishes summaries only, that is what you
  get — the linked article is not fetched.
- Discovery covers the common feed paths and the page's `<link rel="alternate">` tags. A site that
  publishes a feed in neither place will not be found; pass the feed URL directly.
- Podcast enclosures are not downloaded, only linked.
- Paywalled or authenticated feeds are out of scope.

# Actor input Schema

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

RSS, Atom or JSON Feed URLs. A plain site URL works too — the feed is found from the page's own link tags, after checking robots.txt.

## `keyword` (type: `string`):

Keep only items whose title, summary, content or tags match any of these words.

## `since` (type: `string`):

ISO date, e.g. 2026-08-01. Items older than this are dropped. Items with no date are kept.

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

Include the item body as plain text. Turn off for a lighter, cheaper result.

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

0 means no limit.

## Actor input object example

```json
{
  "feeds": [
    "https://news.ycombinator.com/rss",
    "https://github.blog/feed/",
    "https://blog.rust-lang.org"
  ],
  "includeContent": true,
  "maxItemsPerFeed": 0
}
```

# Actor output Schema

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

Every item read, with markup stripped.

## `itemsCsv` (type: `string`):

The same rows as CSV.

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

Which feed each source resolved to and how many items it produced.

# 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://news.ycombinator.com/rss",
        "https://github.blog/feed/",
        "https://blog.rust-lang.org"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("plainapi/rss-atom-json-feed-reader-for-llm").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://news.ycombinator.com/rss",
        "https://github.blog/feed/",
        "https://blog.rust-lang.org",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("plainapi/rss-atom-json-feed-reader-for-llm").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://news.ycombinator.com/rss",
    "https://github.blog/feed/",
    "https://blog.rust-lang.org"
  ]
}' |
apify call plainapi/rss-atom-json-feed-reader-for-llm --silent --output-dataset

```

## MCP server setup

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

```

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/apkv3wKdbB8MN7w70/builds/WIvUG8WZ2hYXfY8Wc/openapi.json
