# rss-feed-converter (`ryumoon-data/rss-feed-converter`) Actor

Convert RSS, Atom, RDF, JSON Feed, podcast and YouTube channel feeds into clean, deduplicated JSON and Markdown. Paste a website and it finds the feed. "Only new items" mode for schedules. $1 per 1,000 items, failed feeds free.

- **URL**: https://apify.com/ryumoon-data/rss-feed-converter.md
- **Developed by:** [Ryu Moon](https://apify.com/ryumoon-data) (community)
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 feed item saveds

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 to JSON & Markdown – Atom, Podcasts, YouTube

**Turn any RSS, Atom, podcast or YouTube channel feed (or just a website address) into clean, deduplicated JSON and Markdown, for $1 per 1,000 items. Feeds that fail are free.**

#### Who it's for

Marketers, newsletter writers, researchers, podcast and media monitors, and AI builders who need a steady stream of fresh posts as tidy data, without writing a feed parser.

#### What people use it for

- 📰 **News and competitor monitoring.** Schedule it daily with *Only new items* on and get just the posts you haven't seen, in Google Sheets, Slack or Notion.
- 🧠 **AI and RAG pipelines.** Every item comes with `contentMarkdown` ready for ChatGPT, Claude or a vector database. Turn on *Fetch full article* when a feed only has teasers.
- 🎙️ **Podcast catalogues.** Episode audio URL, file size, duration in seconds, episode and season numbers, explicit flag.
- 📺 **YouTube channel tracking.** Paste `https://www.youtube.com/@channel` and get the channel's latest videos with video ID, URL, thumbnail and view count. No API key.
- 🚀 **Release tracking.** GitHub `releases.atom` feeds become clean Markdown changelogs.

#### Real sample output

From a real run on the Planet Money podcast feed `https://feeds.npr.org/510289/podcast.xml` (6 Nov 2026, shortened):

```json
{
  "feedTitle": "Planet Money",
  "feedFormat": "rss-podcast",
  "title": "Inside the insurance industry’s destruction lab",
  "link": "https://www.npr.org/2026/11/06/nx-s1-6032860/fire-insurance-industry-destruction-lab",
  "guid": "4dca2240-f1f8-47b7-a504-6aaae5753f74",
  "published": "2026-11-06T22:30:00.000Z",
  "summary": "When you think of someone burning down a house for insurance purposes, you don’t imagine it would ever be the insurance company itself lighting the match…",
  "enclosure": { "url": "https://…/default.mp3", "type": "audio/mpeg", "length": 31091653 },
  "podcast": { "durationSeconds": 1943, "episodeType": "full", "explicit": "no" },
  "wordCount": 321
}
```

And from `https://github.com/nodejs/node/releases.atom` (Atom), the release notes arrive as Markdown:

```json
{
  "feedFormat": "atom",
  "title": "2026-10-29, Version 27.0.0-alpha.0.0.0 (Alpha), @RafaelGSS",
  "link": "https://github.com/nodejs/node/releases/tag/v27.0.0-alpha.0.0.0",
  "published": "2026-10-29T18:36:37.000Z",
  "author": "RafaelGSS",
  "contentMarkdown": "### Notable Changes\n\n#### V8 15.6\n\nThe V8 engine is updated to version 15.6.75.13, up from 14.6 in Node.js 26. Highlights:\n\n- New language features enabled by default: `Math.sumPrecise()`…"
}
```

#### What it costs (real prices)

Pay per event: **$0.001 per item saved**. **No start fee.** Feeds that fail, duplicates, items removed by your filters and items you already had (*Only new items*) are **free**. *Fetch full article* is optional and adds **$0.002** per article, only when the article was fetched successfully.

| Job | Calculation | USD | GBP\* |
|---|---|---|---|
| 1 feed, latest 50 items | 50 × $0.001 | $0.05 | £0.04 |
| 20 news feeds × 50 items | 1,000 × $0.001 | $1.00 | £0.75 |
| Daily monitor, ~30 new posts a day for a month | 900 × $0.001 | $0.90 | £0.67 |
| 100 items + full articles | 100 × ($0.001 + $0.002) | $0.30 | £0.22 |

\*GBP at 1 USD = £0.74711 (ECB rate, 6 Nov 2026). Apify bills in USD. Platform usage for this lightweight HTTP-only Actor runs at 256 MB by default.

### Integrations

All recipes below use Apify's own official integrations. You need a free Apify account.

- **Zapier.** Add Apify as the action in a Zap, pick **Run Actor** (or **Run Task** for a saved example), choose `ryumoon-data/rss-feed-converter` and paste the input JSON. Then add **Fetch dataset items** to pass the results to Google Sheets, Slack, Notion and so on. Synchronous runs in Zapier time out after 30 seconds, so for big batches use the **Finished Actor run** trigger in a second Zap. [Apify docs: Zapier](https://docs.apify.com/platform/integrations/zapier)
- **Make.** Add the Apify module **Run an Actor** with "Run synchronously" set to Yes, then **Get Dataset Items** using the run's default dataset ID, then e.g. Google Sheets "Bulk Add Rows". For long runs, use the **Watch Actor Runs** trigger instead. [Apify docs: Make](https://docs.apify.com/platform/integrations/make)
- **n8n.** Install the Apify node (`@apify/n8n-nodes-apify` from Community Nodes on self-hosted, or search "Apify" in the nodes panel on n8n Cloud). Add an Apify API key or OAuth2 (Cloud) credential, then use it as an action to run this Actor, or as the **On new Apify Event** trigger to process results when a run finishes. [Apify docs: n8n](https://docs.apify.com/platform/integrations/n8n)
- **MCP (Claude, ChatGPT and other AI agents).** Add Apify's hosted MCP server to your client. To load only this Actor, use `https://mcp.apify.com?tools=ryumoon-data/rss-feed-converter`. The first time you connect, your browser opens so you can sign in to Apify. Alternatively, send an `Authorization: Bearer <APIFY_TOKEN>` header:
  ```json
  { "mcpServers": { "apify": { "url": "https://mcp.apify.com?tools=ryumoon-data/rss-feed-converter" } } }
  ```
  Your assistant can then run it from a prompt like *"Get this week's posts from these 5 blogs and summarise them"*. [Apify docs: MCP server](https://docs.apify.com/platform/integrations/mcp)
- **Schedules.** In Apify Console, open a saved task and add a **Schedule** (e.g. every morning at 7:00). With *Only new items* on, each run returns and charges only posts you haven't had yet.

***

Convert **RSS to JSON**, **Atom to JSON** and **RSS to Markdown** in bulk. Paste feed URLs or plain website addresses, set a date filter or keywords, and download clean items as JSON, CSV, Excel or via API. Supports **RSS 2.0, RSS 1.0 (RDF), Atom, JSON Feed, podcast (iTunes) feeds and YouTube channel feeds**.

**$1 per 1,000 items.** No start fee. Failed feeds are free. No API keys, no login, no browser.

### Why this RSS feed converter?

- 🔎 **Paste a website, get its feed.** It reads the page's `<link rel="alternate">` tags, then tries common paths (`/feed`, `/rss.xml`, `/atom.xml`, `/index.xml`, `/feed.json` …). YouTube channel pages (`/@name`) are turned into the channel's video feed automatically.
- 🔁 **Only new items, for schedules.** It remembers what it already delivered, so a daily run returns (and charges) only genuinely new posts.
- 🧹 **Real deduplication.** The same story in two feeds is saved once. Matching uses the GUID, the link with `utm_` tracking removed, and the media URL. Podcasts whose episodes all link to the same show page are *not* wrongly merged.
- 📝 **Markdown, not messy HTML.** Feed content becomes clean Markdown with absolute links and tracking pixels removed. Optional raw HTML too.
- 🎙️ **Podcast fields built in:** audio URL, type and size, `durationSeconds` (from `1:02:03` or seconds), episode, season, episode type, explicit.
- 🕒 **Dates you can sort on.** Every date is ISO 8601 UTC, including RFC 822 dates with `EST`/`PDT`/`BST` zones, wrong weekdays, `Sept`, Unix timestamps and `2024-03-05 10:00:00`.
- ✅ **Bad feeds don't break your run.** A dead link, an HTML page or a broken feed becomes one free error row with a clear `errorCode` (`NO_FEED_FOUND`, `HTTP_404`, `NETWORK_ERROR`, `NOT_A_FEED` …). The rest of the batch carries on.
- 🛡️ **Safe XML.** Entity-expansion tricks in hostile feeds are not expanded, and big feeds aren't rejected by entity limits.

### How to use it

1. Paste **feed URLs or website URLs** (one per line). Mixed lists are fine.
2. Optionally set **Max items per feed**, **Only items since** (`7 days`, `24 hours`, `2026-11-01`) and **Keywords**.
3. For monitoring, turn on **Only new items** and give each monitor its own **Memory name**.
4. Click **Start**, then export the dataset or call it from the API, Make, Zapier, n8n or an AI agent.

#### Input example

```json
{
  "urls": ["https://techcrunch.com", "https://feeds.npr.org/510289/podcast.xml", "https://www.youtube.com/@mkbhd"],
  "maxItemsPerFeed": 20,
  "sinceDate": "7 days",
  "keywords": ["AI", "startup"],
  "onlyNewItems": true,
  "stateKey": "tech-monitor"
}
```

### Output fields

| Field | What it is |
|---|---|
| `feedTitle`, `feedUrl`, `siteUrl`, `feedFormat` | Which feed the item came from. Format is `rss`, `rss-podcast`, `rdf`, `atom`, `atom-youtube` or `json-feed`. |
| `title`, `link`, `guid` | The item. Relative links are made absolute. |
| `published`, `updated` | ISO 8601 UTC dates. |
| `author`, `authors`, `categories` | People and tags (email-only author fields are dropped). |
| `summary` | Plain-text summary, cut at a word boundary (length is configurable). |
| `contentMarkdown` (+ optional `contentHtml`) | The item's content as clean Markdown. |
| `articleMarkdown`, `articleWordCount` | Only with *Fetch full article*. |
| `image`, `enclosure`, `enclosures` | Thumbnail and media files (url, type, length). |
| `podcast` | `durationSeconds`, `episode`, `season`, `episodeType`, `explicit`, `subtitle`. |
| `youtube` | `videoId`, `videoUrl`, `channelId`, `thumbnail`, `views`. |
| `isError`, `errorCode`, `error`, `inputUrl` | Present on free error rows only. |

A run summary (feeds read, items saved, duplicates, filtered, errors, charges) is saved as `SUMMARY` in the key-value store.

### Tips and limits

- Feeds usually hold only the latest 10–100 items; that is a limit of the site's feed, not this Actor. Schedule it to build history over time.
- *Fetch full article* opens each item's web page. Use it only on sites you are allowed to process. For crawling whole sites, use [Website to Markdown for AI, LLM & RAG](https://apify.com/ryumoon-data/website-to-markdown-rag).
- Feeds are public, so a proxy is rarely needed. If a site blocks you, add one under *Proxy*.

### FAQ

**Is it legal?** It reads public feeds that sites publish so they can be read by software. Publishing someone else's full content may need their permission; check the site's terms.

**Can I get older items than the feed shows?** No. A feed only lists recent items. Use *Only new items* on a schedule to keep a complete history from now on.

**What if a feed is broken?** You get one free error row explaining why, and the other feeds still run.

Related: [YouTube Transcript Scraper](https://apify.com/ryumoon-data/youtube-transcript-scraper) to get the full spoken text of the videos this Actor finds in a channel feed, and [Website to Markdown for AI, LLM & RAG](https://apify.com/ryumoon-data/website-to-markdown-rag) to turn whole websites into Markdown for the same AI pipelines.

# Actor input Schema

## `urls` (type: `array`):

Feed URLs (RSS, Atom, RDF, JSON Feed, podcast) OR normal website / YouTube channel URLs. For websites the Actor finds the feed via <link rel="alternate"> tags, then common paths like /feed, /rss.xml and /atom.xml.

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

Newest items first. 0 = every item in the feed.

## `sinceDate` (type: `string`):

Skip older items. A date (2026-11-01) or a relative period: '24 hours', '7 days', '2 weeks', '1 month'. Items with no date are skipped when this is set.

## `onlyNewItems` (type: `boolean`):

Remember what was already delivered and return only items you haven't had before. Ideal with an Apify schedule: you pay only for genuinely new posts.

## `stateKey` (type: `string`):

Use a different name for each separate monitor so their memories don't mix.

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

Keep only items whose title, summary or categories contain at least one of these words (whole-word, case-insensitive).

## `excludeKeywords` (type: `array`):

Drop items containing any of these words.

## `includeContentMarkdown` (type: `boolean`):

Convert each item's HTML content into clean Markdown (links made absolute, tracking pixels removed).

## `includeContentHtml` (type: `boolean`):

Add the original HTML content as contentHtml.

## `summaryMaxChars` (type: `integer`):

Plain-text summary is cut at a word boundary. 0 = no limit.

## `fetchFullArticle` (type: `boolean`):

Many feeds only include a teaser. Turn on to open each item's link and add the full article as clean Markdown (articleMarkdown). Charged only when it succeeds. Only use on sites you are allowed to process.

## `discoverAllFeeds` (type: `boolean`):

Off = use the first (main) feed a website advertises. On = read all of them (e.g. per-category feeds). Duplicates are removed.

## `dedupeAcrossFeeds` (type: `boolean`):

The same story in two feeds is saved (and charged) once. Matching uses GUID, link (ignoring utm\_ tracking parameters) and media URL.

## `sortNewestFirst` (type: `boolean`):

Sort each feed by date before applying the item limit.

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

How many feeds or websites are processed at the same time.

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

How long to wait for each feed or page before giving up. A timed-out feed returns a free error row.

## `proxyConfiguration` (type: `object`):

Usually not needed: feeds are public. Use a proxy only if a site blocks you.

## Actor input object example

```json
{
  "urls": [
    "https://hnrss.org/frontpage",
    "https://github.com/nodejs/node/releases.atom",
    "https://wordpress.org/news/"
  ],
  "maxItemsPerFeed": 50,
  "onlyNewItems": false,
  "stateKey": "default",
  "includeContentMarkdown": true,
  "includeContentHtml": false,
  "summaryMaxChars": 500,
  "fetchFullArticle": false,
  "discoverAllFeeds": false,
  "dedupeAcrossFeeds": true,
  "sortNewestFirst": true,
  "maxConcurrency": 5,
  "requestTimeoutSecs": 30
}
```

# Actor output Schema

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

All feed items in the run's default dataset.

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

Counts of feeds read, items saved, duplicates and errors.

# 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 = {
    "urls": [
        "https://hnrss.org/frontpage",
        "https://github.com/nodejs/node/releases.atom",
        "https://wordpress.org/news/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ryumoon-data/rss-feed-converter").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 = { "urls": [
        "https://hnrss.org/frontpage",
        "https://github.com/nodejs/node/releases.atom",
        "https://wordpress.org/news/",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("ryumoon-data/rss-feed-converter").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 '{
  "urls": [
    "https://hnrss.org/frontpage",
    "https://github.com/nodejs/node/releases.atom",
    "https://wordpress.org/news/"
  ]
}' |
apify call ryumoon-data/rss-feed-converter --silent --output-dataset

```

## MCP server setup

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

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/vMpWOqFiU2s6NWda9/builds/nQDma2bQbOcTeMQwH/openapi.json
