# RSS & Atom Feed Parser (`automation-lab/rss-atom-feed-parser`) Actor

Parse public RSS and Atom feed URLs into normalized feed and item records for monitoring, ingestion, and automation.

- **URL**: https://apify.com/automation-lab/rss-atom-feed-parser.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.48 / 1,000 item extracteds

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?

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 & Atom Feed Parser

Convert anonymous public RSS and Atom feed URLs into consistent JSON records for monitoring, content ingestion, research, and automation. The Actor normalizes feed metadata and entries across RSS 2.0, RSS 1.0/RDF, and Atom 1.0 without requiring an account, browser, or proxy.

Supply one feed or a batch of feeds. Each item includes stable identity, title, link, author, dates, categories, summary, full content, media attachments, source attribution, and retrieval time. Optional feed rows make mixed-source jobs auditable by showing redirects, detected format, item counts, HTTP status, and per-feed errors.

### What does this RSS Atom parser do?

The Actor fetches up to 100 public feed URLs in one run and:

- detects RSS 2.0, RSS 1.0/RDF, or Atom 1.0;
- resolves relative item and attachment links;
- reads common extensions such as `content:encoded`, `dc:creator`, and `dc:date`;
- normalizes valid dates to ISO 8601;
- preserves full-content HTML while also producing plain text;
- extracts RSS enclosures, Media RSS content, and Atom enclosure links;
- deduplicates repeated items by source identifier or a stable derived ID;
- applies one global item limit across all feeds;
- emits a retrieval-status row for every attempted feed by default;
- retries only temporary transport, rate-limit, and server failures.

This Actor parses feeds. It does not crawl linked web pages, discover feeds from websites, compare runs, send alerts, or bypass authentication.

### Who is it for?

**Data engineers** can standardize publisher feeds before loading them into a warehouse, vector database, or search index.

**News and market researchers** can combine feeds from different publishers into one table with consistent dates and source attribution.

**Developers** can replace format-specific XML handling with a scheduled Actor task and consume JSON through the Apify API.

**Automation builders** can send new run results to Make, Zapier, n8n, Google Sheets, Slack, or a webhook.

**AI teams** can collect feed-provided text and metadata for classification, summarization, or retrieval pipelines while retaining canonical links.

### Why use this feed parser?

Feed XML varies even when publishers call it RSS. One source may use `description`; another uses Atom `summary`; another stores the useful body in `content:encoded`. Author and date fields also differ.

The Actor maps those differences into one documented schema. Unlike a monitor, it returns the current feed snapshot on every run. Unlike a full article scraper, it only returns content the publisher places in the feed. This keeps runs lightweight and source behavior transparent.

### Supported feed data

| Output field | Meaning |
| --- | --- |
| `recordType` | `item` for an entry or `feed` for retrieval metadata |
| `itemId` | GUID, Atom ID, or stable derived item ID |
| `title` | Item or feed title without markup |
| `link` | Absolute canonical/alternate item URL |
| `author`, `authors` | Primary and complete author values |
| `publishedAt` | Normalized publication time |
| `updatedAt` | Normalized update time |
| `categories` | RSS category values or Atom terms |
| `summary` | Plain-text description or Atom summary |
| `contentText` | Plain text from full content, or summary fallback |
| `contentHtml` | Feed-provided full-content HTML when available |
| `media` | Enclosures and Media RSS/Atom attachments |
| `sourceFeedUrl` | Original URL from the Actor input |
| `feedTitle` | Parent feed title copied onto each item |
| `retrievalStatus` | `success` or `error` |
| `httpStatus` | HTTP status on a successful feed row |
| `itemCount` | Parsed items before the global output limit |
| `emittedItemCount` | Items emitted from one feed |
| `errorMessage` | Concise feed-level error when retrieval fails |
| `retrievedAt` | ISO timestamp for the retrieval attempt |

Fields that publishers omit are returned as `null` or an empty array where appropriate.

### How to parse an RSS Atom feed

1. Open the Actor in Apify Console.
2. Add one or more public URLs to **Feed URLs**.
3. Choose the maximum number of item records.
4. Keep **Include feed status records** enabled when you want an audit row per URL.
5. Run the Actor.
6. Open the dataset and export JSON, CSV, Excel, XML, or RSS from Apify.
7. Save the input as a Task if you want recurring runs.

A useful first input is:

```json
{
  "feedUrls": [
    { "url": "https://www.nasa.gov/rss/dyn/breaking_news.rss" },
    { "url": "https://github.com/nodejs/node/releases.atom" }
  ],
  "maxItems": 30,
  "includeFeedRecords": true
}
```

### Input parameters

#### `feedUrls`

Required array of 1–100 anonymous public HTTP(S) RSS or Atom URLs. Strings and request-list objects with a `url` field are accepted. Duplicate URL strings are fetched once.

URLs containing credentials, local hostnames, loopback addresses, or private-network destinations are rejected. Redirect destinations receive the same validation.

#### `maxItems`

Maximum number of **item** records emitted across the entire run. Default: `1000`. Range: `1`–`10000`.

Feed status rows are operational metadata and do not count against this item limit.

#### `includeFeedRecords`

Whether to add one feed-level status record after each attempt. Default: `true`.

Disable it when a downstream table should contain item rows only. Per-feed failures still appear in logs. If every feed fails, the run fails rather than silently returning an empty success.

#### `requestTimeoutSecs`

Per-request timeout in seconds. Default: `30`. Range: `5`–`120`.

#### `maxRetries`

Retries for network errors, timeouts, HTTP 408/425/429, and temporary 5xx responses. Default: `2`. Range: `0`–`4`. Permanent HTTP errors and invalid XML are not retried blindly.

### Output example

A normalized item resembles:

```json
{
  "recordType": "item",
  "itemId": "tag:github.com,2008:Repository/27193779/v22.0.0",
  "title": "Node.js v22.0.0",
  "link": "https://github.com/nodejs/node/releases/tag/v22.0.0",
  "author": "Sample Maintainer",
  "authors": ["Sample Maintainer"],
  "publishedAt": null,
  "updatedAt": "2025-01-15T12:00:00.000Z",
  "categories": [],
  "summary": "Release notes for this version.",
  "contentText": "Release notes for this version.",
  "contentHtml": "<p>Release notes for this version.</p>",
  "media": [],
  "sourceFeedUrl": "https://github.com/nodejs/node/releases.atom",
  "feedTitle": "Release notes from node",
  "retrievalStatus": "success",
  "retrievedAt": "2025-01-15T12:05:00.000Z"
}
```

A feed row resembles:

```json
{
  "recordType": "feed",
  "title": "Release notes from node",
  "format": "atom",
  "sourceFeedUrl": "https://github.com/nodejs/node/releases.atom",
  "finalUrl": "https://github.com/nodejs/node/releases.atom",
  "retrievalStatus": "success",
  "httpStatus": 200,
  "itemCount": 10,
  "emittedItemCount": 10,
  "errorMessage": null,
  "retrievedAt": "2025-01-15T12:05:00.000Z"
}
```

### How limits work across multiple feeds

`maxItems` is global. Feeds are processed in input order. If the first feed contains 20 items and `maxItems` is 25, at most five item rows are taken from the next feed. Processing stops once the limit is reached.

Put higher-priority feeds first when the limit is lower than the combined feed volume. Increase the limit when every current item matters.

### How much does it cost to parse RSS and Atom feed items?

Pricing uses pay per event:

- **Start:** $0.001 once per run.
- **Feed item:** $0.00092 on Free, $0.0008 on Bronze, $0.000624 on Silver, and $0.00048 on Gold, Platinum, and Diamond.
- Feed status rows have no separate event charge.

At Free pricing, a run returning 10 items costs about **$0.0102** including start. A 100-item run costs about **$0.093**, and a 1,000-item run costs about **$0.921**. Apify platform usage may be billed according to your plan and the active pricing shown in Console; the Console estimate is authoritative.

Use one scheduled batch for several feeds when that matches your workflow, because the start event is charged once per run.

### Scheduling recurring feed ingestion

Create an Apify Task with a stable list of feed URLs, then attach an hourly, daily, or weekly schedule. Each run returns the feed's current snapshot. Your downstream system can compare stable `itemId` values and `updatedAt` timestamps to identify new or changed entries.

The Actor itself does not persist prior snapshots or label changes. Use a dataset, database, webhook consumer, or the related RSS Feed Article Monitor when stateful change events are required.

### Export and integration workflows

- **Google Sheets:** export the dataset as CSV/Excel or connect through Make.
- **Data warehouse:** request JSON from the dataset API after each scheduled run.
- **n8n:** call the Actor, wait for completion, then iterate through item records.
- **Zapier or Make:** use the Apify integration and filter `recordType = item`.
- **Webhook:** attach a run-succeeded webhook and fetch `defaultDatasetId`.
- **AI pipeline:** send `title`, `summary`, and `contentText` to classification or embedding steps while retaining `link` and `sourceFeedUrl`.

### Run through the Apify API

Replace `YOUR_TOKEN` with your Apify token.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~rss-atom-feed-parser/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"feedUrls":[{"url":"https://github.com/nodejs/node/releases.atom"}],"maxItems":20}'
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/rss-atom-feed-parser').call({
  feedUrls: [{ url: 'https://github.com/nodejs/node/releases.atom' }],
  maxItems: 20,
  includeFeedRecords: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((item) => item.recordType === 'item'));
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient(token="YOUR_TOKEN")
run = client.actor("automation-lab/rss-atom-feed-parser").call(run_input={
    "feedUrls": [{"url": "https://github.com/nodejs/node/releases.atom"}],
    "maxItems": 20,
    "includeFeedRecords": True,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print([item for item in items if item["recordType"] == "item"])
```

### Use with MCP and AI agents

Add this Actor as an Apify MCP tool in Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/rss-atom-feed-parser"
```

#### Claude Desktop, Cursor, and VS Code setup

Claude Desktop, Cursor, and VS Code clients can use:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/rss-atom-feed-parser"
    }
  }
}
```

Example prompts:

- “Parse the Node.js releases Atom feed and list release title, link, and update time.”
- “Combine these three public news feeds, return only item rows, and group titles by source feed.”
- “Run the RSS parser daily and send the resulting dataset to my ingestion workflow.”

### Reliability and failure behavior

The Actor checks HTTP status, validates the response as a supported feed, limits buffered XML to 10 MB, follows at most five redirects, and uses bounded retries. It records an error feed row when one URL fails but other feeds succeed.

The entire run fails when no feed can be parsed. This prevents malformed XML, challenge pages, and authentication screens from looking like valid empty feeds.

Feed publishers can change formats or temporarily block cloud traffic. Inspect `errorMessage`, HTTP logs, and the original URL. Confirm that the URL opens as XML without a login.

### Limitations

- Only anonymous public HTTP(S) feeds are supported.
- RSS 2.0, RSS 1.0/RDF, and Atom 1.0 are supported; JSON Feed and sitemaps are not.
- Website feed auto-discovery is not included.
- Linked article pages are not fetched, so `contentText` contains only feed-provided content.
- Invalid source dates become `null` rather than guessed timestamps.
- The Actor does not preserve state, identify changes, or send alerts.
- A single feed response cannot exceed 10 MB.
- Private-network and credential-bearing URLs are blocked for safety.

### Legality and responsible use

RSS and Atom are publisher-provided syndication formats, but access does not automatically grant every reuse right. Follow the publisher's terms, copyright rules, licenses, and applicable law. Keep source links and attribution where required. Do not use the Actor to retrieve confidential, authenticated, or personal feeds.

The user is responsible for input URLs, scheduling frequency, storage, and downstream use.

### Troubleshooting

#### Why did my feed return “not a supported feed”?

The URL may return an HTML page, bot challenge, JSON, or malformed XML instead of RSS/Atom. Open the URL directly and inspect its content type and root element. Supply the feed endpoint itself, not the publication home page.

#### Why is `contentHtml` null?

Many feeds publish only a summary. `contentText` falls back to that summary, but the Actor does not visit the linked article to obtain a full body.

#### Why are some feeds missing when I use a low limit?

Processing stops after `maxItems` item rows. Increase the limit or place priority feeds first.

#### Can I parse a private or password-protected feed?

No. The Actor intentionally supports anonymous public feeds only and rejects embedded credentials and private-network destinations.

### Frequently asked questions

#### Does it support podcast feeds?

Yes, when they use supported RSS/Atom syntax. Audio enclosures appear in `media` with URL, MIME type, byte length, and title when supplied.

#### Does it deduplicate across runs?

No. Duplicate IDs inside one feed response are collapsed. Cross-run change tracking belongs in your downstream system or the RSS Feed Article Monitor.

#### Can it parse many publishers in one run?

Yes. Supply up to 100 URLs and use one global limit of up to 10,000 item records.

#### Are feed status rows charged as items?

No. The per-item event applies only to normalized `recordType: item` rows. Feed status rows are included without a separate event.

### Related automation-lab Actors

- [RSS Feed Article Monitor](https://apify.com/automation-lab/rss-feed-article-monitor) — persistent new, updated, and confirmed-removed article events with keyword rules.
- [Multi-Site Article Content Extractor](https://apify.com/automation-lab/multi-site-article-content-extractor) — fetch linked pages when you need article-page metadata and content beyond the feed.

Choose this Actor for a normalized current snapshot. Choose the monitor for stateful changes, or the article extractor for page-level enrichment.

# Actor input Schema

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

Public HTTP(S) RSS or Atom URLs. Duplicates are removed; private, local, and authenticated URLs are rejected.

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

Maximum number of item records emitted across all feeds. Feed status records do not count toward this limit.

## `includeFeedRecords` (type: `boolean`):

Emit one feed record with metadata, HTTP status, item counts, and any retrieval error for each attempted feed.

## `requestTimeoutSecs` (type: `integer`):

Per-request timeout. Increase only for known slow public feed servers.

## `maxRetries` (type: `integer`):

Retries for timeouts, rate limits, and temporary server errors. Invalid feeds and permanent HTTP errors are not retried.

## Actor input object example

```json
{
  "feedUrls": [
    {
      "url": "https://feeds.bbci.co.uk/news/world/rss.xml"
    },
    {
      "url": "https://hnrss.org/frontpage"
    }
  ],
  "maxItems": 20,
  "includeFeedRecords": true,
  "requestTimeoutSecs": 30,
  "maxRetries": 2
}
```

# Actor output Schema

## `overview` (type: `string`):

Open normalized RSS/Atom items and feed status rows in the overview table.

# 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": [
        {
            "url": "https://feeds.bbci.co.uk/news/world/rss.xml"
        },
        {
            "url": "https://hnrss.org/frontpage"
        }
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/rss-atom-feed-parser").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": [
        { "url": "https://feeds.bbci.co.uk/news/world/rss.xml" },
        { "url": "https://hnrss.org/frontpage" },
    ],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/rss-atom-feed-parser").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": [
    {
      "url": "https://feeds.bbci.co.uk/news/world/rss.xml"
    },
    {
      "url": "https://hnrss.org/frontpage"
    }
  ],
  "maxItems": 20
}' |
apify call automation-lab/rss-atom-feed-parser --silent --output-dataset

```

## MCP server setup

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

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/529G9CGrFwbE43xSC/builds/RSrZhgIbdzIunkSYW/openapi.json
