# RSS Feed Scraper: RSS or Atom Feed to JSON, New Items Only (`deriverge/rss-feed-scraper`) Actor

Scrape any RSS or Atom feed to clean JSON: title, link, date, author, categories, summary, full text and enclosure URL. Many feeds per run, filter by date and keyword, get only new items since your last run. CSV, Excel, API and schedules.

- **URL**: https://apify.com/deriverge/rss-feed-scraper.md
- **Developed by:** [deriverge s.r.o.](https://apify.com/deriverge) (community)
- **Categories:** News, Social media, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.45 / 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 Scraper

RSS Feed Scraper reads RSS 2.0, RSS 1.0 (RDF) and Atom feeds and returns one row per item: title, link, publication time in UTC, author, categories, a plain-text summary and, on request, the full text the feed carries. Podcast feeds also give the audio file, its length and the episode type. Paste feed URLs into **Feed URLs** and click **Start**; a run over ten feeds returned 259 items in under 5 seconds in October 2026. It needs the feed address itself and does not search a homepage for one. It costs $0.90 per 1,000 feed items on the Free plan ($0.45 on Business), and the $5 of monthly credit in Apify's Free plan covers about 5,500 feed items.

### What data does it return?

| Field | Description |
|---|---|
| `title`, `link` | Item title and the page it points to, usually the article or episode page. `link` is `null` when the feed lists none. |
| `publishedAt` | Publication time from the feed's `pubDate`, `dc:date` or Atom `published` (or `updated`), converted to ISO 8601 UTC, such as `2026-10-11T15:15:00.000Z`. `null` when the feed gives no date. |
| `author` | Author as the feed lists it for the item (`author`, `dc:creator`, `itunes:author` or the Atom author name), otherwise the author of the whole feed. BBC News lists none. |
| `summary` | The item description as plain text, with HTML tags removed and paragraphs kept as line breaks. Cut to 300 characters ending in `...` unless **Full text** is on. |
| `content` | With **Full text** on, the whole text the feed carries for the item (`content:encoded` or Atom `content`, falling back to the description), as plain text. Otherwise `null`. |
| `categories` | Category or tag labels of the item, such as `Movie Review`. An empty list when the feed has none. |
| `image` | The item image from `itunes:image`, otherwise the logo of the feed. |
| `audioUrl`, `audioType`, `audioBytes` | The file attached as an enclosure, its MIME type such as `audio/mpeg`, and its size in bytes as the feed declares it. A few blogs attach a picture here, which then shows as `image/png`. |
| `durationSeconds`, `episodeNumber`, `seasonNumber`, `episodeType`, `explicit` | Podcast tags: length in seconds, episode and season number, `full`, `trailer` or `bonus`, and the explicit flag. `null` in news and blog feeds. |
| `feedTitle`, `feedUrl` | Title the feed gives itself, such as `BBC News`, and the feed URL you entered. |
| `guid`, `key` | The item ID from the feed (RSS `guid`, RDF `rdf:about` or Atom `id`, otherwise the enclosure URL or the link), and the row key made of feed URL and ID, which new-only mode compares between runs. |
| `podcastName`, `podcastKey`, `podcastAppleId`, `appleUrl`, `episodeSource`, `type` | Fields shared with our podcast actors. Here `podcastName` repeats the feed title, `podcastAppleId` and `appleUrl` are always `null`, `episodeSource` is `rss` and `type` is `item`. |

### How to scrape RSS and Atom feeds

1. Enter one or more addresses in **Feed URLs**, one per line. Each must return the feed XML itself, such as `https://feeds.bbci.co.uk/news/rss.xml`. Sites usually link their feed in the page header or serve it at `/feed` or `/rss`.
2. Set **Maximum items per feed** (100 by default). Items are sorted newest first, so a low number keeps the latest ones.
3. To narrow the output, add **Keywords (any of)**, matched as whole words or phrases in the title, summary and categories, or a **Published after** date. Items without a date pass the date filter.
4. Turn on **Full text** when you need whole articles or show notes in `content`.
5. Click **Start**. Items appear in the **Output** tab and can be downloaded as JSON, CSV or Excel. The `SUMMARY` record in the run's key-value store counts the items under `itemsFound` and `itemsReturned`, lists unreadable feeds under `feedsFailed` and counts the items each filter removed under `droppedByFilter`.

An input for the API that watches two feeds for new items about datacentres or open source:

```json
{
  "feeds": ["https://www.theguardian.com/uk/technology/rss", "https://blog.cloudflare.com/rss/"],
  "maxItemsPerFeed": 50,
  "keywords": ["datacentre", "open source"],
  "publishedAfter": "2026-10-01",
  "includeContent": true,
  "newOnly": true,
  "watchName": "tech-news"
}
```

### Example output

One item from The Verge in a run on 11 October 2026 with default settings. The actor cut `summary` at 300 characters, and `content` is `null` because **Full text** was off.

```json
{
  "type": "item",
  "key": "episode:podcast:feed:https://www.theverge.com/rss/index.xml:https://www.theverge.com/?p=1009346",
  "podcastKey": "podcast:feed:https://www.theverge.com/rss/index.xml",
  "podcastAppleId": null,
  "podcastName": "The Verge",
  "feedTitle": "The Verge",
  "feedUrl": "https://www.theverge.com/rss/index.xml",
  "title": "George A. Romero’s Season of the Witch is a slow-burn feminist occult drama",
  "link": "https://www.theverge.com/entertainment/1009346/george-a-romero-season-of-the-witch-feminist-horror-review",
  "appleUrl": null,
  "publishedAt": "2026-10-11T15:15:00.000Z",
  "durationSeconds": null,
  "episodeNumber": null,
  "seasonNumber": null,
  "episodeType": null,
  "explicit": null,
  "author": "Terrence O’Brien",
  "summary": "George A. Romero is obviously best known as the father of the modern zombie movie. But between inventing the genre with Night of the Living Dead and his outbreak horror, The Crazies, Romero made two much lesser-known films: There's Always Vanilla, which I'll admit I've never seen, and Season of t...",
  "content": null,
  "categories": [
    "Column",
    "Entertainment",
    "Film",
    "Movie Review"
  ],
  "image": "https://platform.theverge.com/wp-content/uploads/sites/2/2025/01/verge-rss-large_80b47e.png?w=150&h=150&crop=1",
  "audioUrl": null,
  "audioType": null,
  "audioBytes": null,
  "guid": "https://www.theverge.com/?p=1009346",
  "episodeSource": "rss"
}
```

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

| | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| 1,000 feed items | $0.90 | $0.72 | $0.585 | $0.45 |

You pay only for the events in the table. There is no start fee, and compute time and proxies are included.

A daily run over 100 feeds with 50 items each returns at most 5,000 items, $4.50 on the Free plan and $2.25 on Business. You pay only for rows written: items removed by a filter, items already returned in new-only mode and feeds that could not be read cost nothing.

### Limits and known issues

- A feed holds only what the publisher keeps in it. In the October 2026 test, The Verge and NASA served 10 items each, BBC News 25, the Guardian technology feed 32 and the Planet Money podcast 355. Older items that left the feed cannot be read.
- RSS 2.0, RSS 1.0 (RDF) and Atom are supported; Slashdot's RDF feed gave 15 items in the October 2026 test. JSON Feed is not read, and a feed whose items cannot be read is listed in `feedsFailed`.
- `content` holds only the text the publisher puts in the feed. BBC News sends a one-sentence description, so for whole articles open `link` with an article extractor.
- Keywords match whole words and ignore case, and a keyword of several words matches as a phrase. `ai` keeps items about AI but not items that only contain `said`, and `datacentre` does not match `datacentres`, so add plural forms you want.
- Up to 4 feeds are read at a time. Each request waits up to 60 seconds and is repeated twice after a server error or HTTP 429. A feed that still fails, or returns something other than RSS or Atom, is listed in `feedsFailed`. If fewer than half of the feeds can be read, the run ends as failed.
- The whole run returns at most the number set in **Maximum rows**, 5,000 by default.
- Items without a `guid`, an enclosure or a link get an ID made of title and date, so editing the title of such an item makes it count as new.

### Watching feeds for new items

Turn on **Return only rows new since the last run** and set a **Watch name**, or save the input as a task, which gets its own snapshot automatically. Then add a schedule, hourly or daily. Each run returns only items whose `key` the previous run of that watch did not have; the first run returns everything and saves the snapshot. Items cut off by **Maximum rows** are kept for the next run.

Every run with a watch also writes a `CHANGES` record with `added` and `removed` counts and the keys of the items concerned. The snapshot holds the items the feed listed last time, so an item that drops out of the feed and reappears later counts as new again.

### FAQ

#### Is it legal to scrape RSS feeds?

Publishers offer RSS and Atom feeds so that readers and apps can fetch them, and the actor requests only the feed URLs you enter, without logging in. Rows contain what the publisher put in the feed, including the bylines of article authors. Republishing full text can infringe the publisher's copyright, and you are responsible for how you use the data.

#### Can I find the feed of a website with it?

No. The actor needs the feed address. On most news sites and blogs it is linked in the page source as `application/rss+xml`, or sits at `/feed`, `/rss` or `/atom.xml`.

#### Does it read podcast feeds?

Yes. Any podcast RSS feed works, with the audio URL, file size, duration, episode type and the explicit flag. To search Apple Podcasts or read its charts, use the Apple Podcasts actor listed below.

#### Why is `author` or `publishedAt` empty for some items?

The feed did not publish it. `author` falls back to the author of the whole feed when an item has none; other values are never filled in by the actor, so a missing value is `null`.

### Related scrapers

- [Apple Podcasts Scraper](https://apify.com/deriverge/apple-podcasts-scraper)
- [Google News Scraper](https://apify.com/deriverge/google-news-scraper)
- [Article Extractor](https://apify.com/deriverge/article-extractor)
- [Substack Scraper](https://apify.com/deriverge/substack-scraper)
- [Sitemap Extractor](https://apify.com/deriverge/sitemap-extractor)

### Support

This actor is built and maintained by deriverge s.r.o., a software company based in the Czech Republic. If a run fails or a field you need is missing, please open an issue in the **Issues** tab or write to us at info@deriverge.com. We respond in English and Czech. Runs can be scheduled in Apify Console or started from the **API** tab, which has examples for Python, JavaScript and cURL and works with Make, Zapier, n8n and the Apify MCP server. If the actor saves you time, a short review helps other people find it.

# Changelog

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

# Actor input Schema

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

RSS 2.0 or Atom feed URLs, as many as you like. Podcast feeds work too and carry the audio enclosure.

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

Newest first.

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

Drop items older than this date (YYYY-MM-DD). Items without a date are kept. Dropped items are never charged.

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

Keep only items whose title, summary or categories contain at least one of these words or phrases as whole words, case-insensitive. Dropped items are never charged.

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

Return the complete item text as plain text in the content field. Otherwise summary holds the first 300 characters and content is null.

## `newOnly` (type: `boolean`):

Keeps a snapshot per watch name (or per saved task) and returns only items that were not there before. Schedule it hourly or daily and you have a feed alert that bills only for what is new.

## `watchName` (type: `string`):

Name of the snapshot used by the new-only mode, for example "true-crime-us". Runs from a saved task get a snapshot automatically even without a name.

## `maxItems` (type: `integer`):

Hard cap on returned items across all feeds in the run.

## Actor input object example

```json
{
  "feeds": [
    "https://www.theverge.com/rss/index.xml",
    "https://feeds.bbci.co.uk/news/rss.xml"
  ],
  "maxItemsPerFeed": 100,
  "includeContent": false,
  "newOnly": false,
  "maxItems": 5000
}
```

# Actor output Schema

## `rows` (type: `string`):

One row per feed item with title, link, date, author, categories, summary, full text on request and the enclosure for podcast feeds.

## `changes` (type: `string`):

Items that appeared or disappeared compared with the previous snapshot of the same watch name or task.

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

Counts per source, how many rows each filter dropped, feeds that could not be read and notes.

# 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://www.theverge.com/rss/index.xml",
        "https://feeds.bbci.co.uk/news/rss.xml"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("deriverge/rss-feed-scraper").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://www.theverge.com/rss/index.xml",
        "https://feeds.bbci.co.uk/news/rss.xml",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("deriverge/rss-feed-scraper").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://www.theverge.com/rss/index.xml",
    "https://feeds.bbci.co.uk/news/rss.xml"
  ]
}' |
apify call deriverge/rss-feed-scraper --silent --output-dataset

```

## MCP server setup

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

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/6G0BBMd820awvL35n/builds/mat4ZWLwiGwO96ZtB/openapi.json
