RSS and Atom to JSON avatar

RSS and Atom to JSON

Pricing

from $0.50 / 1,000 feed items

Go to Apify Store
RSS and Atom to JSON

RSS and Atom to JSON

Turn RSS, Atom and JSON Feed URLs into clean, deduplicated JSON rows, with optional full article text. $0.0005 per item.

Pricing

from $0.50 / 1,000 feed items

Rating

0.0

(0)

Developer

Comrade Coding

Comrade Coding

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 hours ago

Last modified

Categories

Share

Give it a list of feed URLs. It reads RSS 2.0, RSS 1.0, Atom, and JSON Feed, and returns every item as one flat JSON row with the same field names whatever the format: title, link, author, published and updated dates in ISO 8601 UTC, a plain-text summary, categories, image, and enclosure (podcast audio and similar). Items that appear in more than one feed come back once.

Two options go further:

  • Full text. Turn on fetchFullText and the actor opens each item's link and adds the main text of the page as Markdown. Useful when a feed only carries a one-line teaser.
  • Only new items. Set seenItemsStore to a name, run the actor on a schedule, and each run returns only items that earlier runs with the same name have not already returned.

Typical uses: feeding news or blog posts into a database, a search index, or a language model; watching release notes from many projects in one table; turning a podcast feed into a list of episodes and audio links.

What it does with each feed URL

  1. Checks the site's robots.txt. If the URL is disallowed, it is skipped. If robots.txt sets a Crawl-delay, the actor waits that long between requests to that site.
  2. Downloads the feed (up to 20 MB) and works out its text encoding from the byte order mark, the server's header, and the XML declaration. When a server says UTF-8 but sends Latin-1 or Windows-1252 bytes, the declaration wins, so accented letters come through intact. Feeds in KOI8-R, Windows-1251, Shift_JIS and other legacy encodings are decoded too.
  3. If the URL is a web page instead of a feed, it follows the first feed the page declares in a <link rel="alternate"> tag. So https://github.blog/ works as well as https://github.blog/feed/.
  4. Parses the items, fixes dates that do not follow the standard (missing time zone, zone names such as CEST, full month names), makes links absolute, and turns HTML descriptions into plain text.
  5. Sorts items newest first when every item has a date. If any item has no date, the feed's own order is kept.
  6. Drops items older than publishedAfter, items already returned in this run (same id, or same link once tracking parameters such as utm_source are removed), and items returned by earlier runs if seenItemsStore is set. Then keeps up to maxItemsPerFeed.

Input

FieldTypeDefaultWhat it does
feedUrlsarrayrequired, no defaultFeed URLs, or web pages that link to a feed. Plain strings or { "url": "..." } objects. A bare host like example.com/feed gets https://. Duplicates are dropped.
maxItemsinteger1000Stop after this many items in total. Caps what a run costs you.
maxItemsPerFeedinteger100At most this many items from each feed.
publishedAfterstringemptySkip items older than a date (2026-10-01) or an age (24 hours, 7 days, 2 weeks, 3 months). Items with no date are kept.
fetchFullTextbooleanfalseOpen each item's link and add the page text as Markdown. Charged as an extra event, see Pricing.
includeContentHtmlbooleanfalseAdd content_html, the item body exactly as the feed gives it.
seenItemsStorestringemptyName of a key-value store in your account. Items returned by earlier runs that used the same name are skipped.

Example input:

{
"feedUrls": [
{ "url": "https://blog.rust-lang.org/feed.xml" },
{ "url": "https://www.nasa.gov/feed/" },
{ "url": "https://github.blog/" }
],
"maxItems": 200,
"maxItemsPerFeed": 20,
"publishedAfter": "7 days",
"fetchFullText": false,
"seenItemsStore": "my-news-feeds"
}

Output

One dataset item per feed item. This is a real result from a test run, with the summary cut short here.

{
"source_url": "https://blog.rust-lang.org/feed.xml",
"fetched_at": "2026-10-28T06:47:35.939Z",
"feed_url": "https://blog.rust-lang.org/feed.xml",
"feed_type": "atom",
"feed_title": "Rust Blog",
"feed_link": "https://blog.rust-lang.org/",
"item_key": "d9dbdedb3165d766f60d8f68",
"item_id": "https://blog.rust-lang.org/2026/10/20/Rustup-1.29.2/",
"url": "https://blog.rust-lang.org/2026/10/20/Rustup-1.29.2/",
"title": "Announcing rustup 1.29.2",
"author": "The Rustup Team",
"published_at": "2026-10-20T00:00:00.000Z",
"updated_at": "2026-10-20T00:00:00.000Z",
"summary": "The rustup team is happy to announce the release of rustup version 1.29.2.\n\n...",
"categories": [],
"image_url": null,
"enclosure_url": null,
"enclosure_type": null,
"enclosure_length": null,
"comments_url": null,
"language": "en"
}

With fetchFullText on, each row also has these fields. This example is another item from the same test run:

{
"full_text_url": "https://blog.rust-lang.org/2026/10/15/Rust-1.99.1/",
"full_text_title": "Announcing Rust 1.99.1 | Rust Blog",
"full_text_markdown": "The Rust team has published a new point release of Rust, 1.99.1. ...\n\n```\nrustup update stable\n```\n\n...",
"full_text_word_count": 347,
"full_text_error": null
}

Fields:

  • source_url: the URL you gave. feed_url: the feed actually read, after redirects or after following a page's feed link.
  • fetched_at: ISO 8601 time the feed was downloaded.
  • feed_type: rss-2.0, rss-0.91 and other RSS versions, rss-1.0, atom, json-feed-1, or json-feed-1.1.
  • feed_title, feed_link, language: from the feed itself. null when it does not set them.
  • item_key: a stable 24-character key for the item, the same on every run. Use it to deduplicate in your own database. It is built from the item's id (scoped to the feed's host), else its link, else its title and date.
  • item_id: the item's guid (RSS) or id (Atom, JSON Feed) as written.
  • url: the item's link. For RSS items without a link, a permalink guid is used.
  • title, author: plain text. RSS authors written as email (Name) keep only the name. Several Atom authors are joined with commas. Falls back to the feed's author.
  • published_at, updated_at: ISO 8601 UTC, or null when the feed gives no date or one that cannot be read. Many Atom feeds only set updated_at.
  • summary: plain text of the description, or of the content when there is no description. Paragraphs are separated by a blank line, list items start with - . Up to 3,000 characters, cut at a word with ....
  • categories: RSS categories, Atom category terms, or JSON Feed tags.
  • image_url: from media:thumbnail, media:content, itunes:image, an image enclosure, the JSON Feed image, or the first image in the content.
  • enclosure_url, enclosure_type, enclosure_length: the first enclosure or attachment (length in bytes, as the feed states it).
  • comments_url: the item's comments page when the feed gives one.
  • content_html: only when includeContentHtml is on. The body as the feed gives it, up to 500,000 characters.
  • full_text_*: only when fetchFullText is on. full_text_markdown is the main text of the linked page (up to 1,000,000 characters). When the page could not be read, the feed fields are still returned and full_text_error says why, for example HTTP 404, Disallowed by robots.txt, or Not a web page (server sent application/pdf).

Feeds that fail are not added to the dataset and are not charged. They are listed in the FAILED_URLS record in the run's key-value store with a reason, for example HTTP 404, Got an HTML page that does not link to a feed, Disallowed by robots.txt, or Not a feed: root element is <note>. A SUMMARY record in the same store gives the counts for the run, including how many items were skipped as too old, duplicates, seen before, or over the per-feed cap, and why the run stopped.

Limits

  • Public feeds only. It does not log in or send cookies, so private or members-only feeds fail.
  • It reads what the feed contains at the moment of the run. Most feeds hold only the last 10 to 50 items; older items are not fetched from the site's archive.
  • Feeds over 20 MB and pages over 5 MB are skipped.
  • XML that is badly broken (cut off in the middle, for example) fails with a reason. Common mistakes such as HTML entities like &nbsp; in XML, dates without a time zone, or a wrong charset header are handled.
  • Full text uses the same main-content extraction as a reader view. It works well on articles and blog posts. Pages that are mostly images, or built entirely with JavaScript, return little useful text. Full text is not fetched from sites whose robots.txt asks for more than 10 seconds between requests; those rows get a full_text_error and are not charged the full-text event.
  • Requests go out one at a time, with a 300 to 800 ms pause between requests to the same site, or the site's Crawl-delay if longer. Sites that ask for more than 120 seconds are skipped. With full text on, expect about one second per item, more on sites with a crawl delay.
  • Redirects are followed up to 5 times, and robots.txt is checked for each target, including a different site, before it is requested.
  • Feeds that declare their own XML entities (a DOCTYPE with ENTITY lines) fail with a reason and are not charged. Ordinary feeds do not use them.
  • If a site's robots.txt cannot be reached (server error or timeout), that site is skipped rather than guessed at.
  • seenItemsStore remembers the most recent 100,000 item keys per store name. The store lives in your Apify account until you delete it. Items cut off by maxItems are not marked as seen, so the next run picks them up.
  • Output keeps whatever the feed and pages contain, including author names and any personal details the publisher printed. Check that you may use the content you collect.

Pricing

Pay per event:

  • $0.0005 per item ($0.50 per 1,000) for each item saved to the dataset.
  • $0.0015 extra per item with full text ($1.50 per 1,000), only when fetchFullText is on and the page was read. So an item with full text costs $0.002 in total.

Failed feeds, skipped items, and failed full-text fetches cost nothing extra.

What a run costs:

RunFeed items onlyWith full text
10 feeds, 20 items each (200 items)$0.10$0.40
1,000 items (the default maxItems)$0.50$2.00
10,000 items$5.00$20.00

A schedule that checks 20 feeds every hour with seenItemsStore set, and finds about 5 new items each hour, saves about 3,600 items a month: $1.80 a month without full text.

Set maxItems to cap the cost of a run. You can also set a maximum cost per run in Apify, and the actor stops when it is reached.

This actor is not affiliated with any of the sites used in the examples.

Use it from an AI agent

Add this actor as a tool through Apify's MCP server: https://mcp.apify.com?tools=comradecoding/rss-to-json. The agent gets one clean, deduplicated JSON row per feed item, with optional full article text.

Integrations

Anything that can call the Apify API can run this actor: the Apify API and client libraries, and Apify's integrations for Make, n8n, Zapier and LangChain. Results come back as a dataset you can download as JSON, CSV or Excel.

FAQ

Which feed formats work?

RSS, Atom and JSON Feed.

Can it fetch older items than the feed shows?

No. Most feeds hold the last 10 to 50 items, and it reads what the feed contains at run time.

How do I get only new items on a schedule?

Set seenItemsStore to a name. Each run skips items it has already returned.

Am I charged for full text that fails?

No. Rows where full text could not be fetched get a full_text_error and are not charged the full-text event.