RSS Feed Scraper - Atom & JSON Feed Reader, New Item Monitor
Pricing
from $4.38 / 1,000 feed item returneds
RSS Feed Scraper - Atom & JSON Feed Reader, New Item Monitor
Give it feed URLs or plain website URLs. It finds the feed a site advertises, reads RSS 2.0, RSS 1.0/RDF, Atom and JSON Feed in any encoding, and returns one row per item with title, link, dates, author, summary, full text, categories, image and enclosures. Monitoring mode returns only new items.
Pricing
from $4.38 / 1,000 feed item returneds
Rating
0.0
(0)
Developer
NeverEmpty
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
RSS Feed Scraper — read RSS, Atom and JSON Feed, find a site's feed, watch for new items
Give it feed URLs, or plain website URLs. github.blog is enough.
For a website, it reads the feed the page itself advertises with <link rel="alternate" type="application/rss+xml">
(or Atom / JSON Feed). Then it returns one row per item: title, link, published and updated dates, author,
summary, full text, categories, image, enclosures (podcast audio), duration, guid, and which feed it came from.
It reads RSS 2.0, RSS 1.0 / RDF, Atom and JSON Feed (1.0 and 1.1), in any character encoding.
Real feeds are messier than the specs
Measured on 2026-09-12 against more than 30 live feeds. Every case below is in this Actor's tests, using the real feed:
| Feed | What it does | What this Actor does |
|---|---|---|
| soumu.go.jp (Japanese government) | Shift_JIS, and the server does not say so — only the XML declaration does | Reads the XML declaration, returns clean Japanese |
| Slashdot | Declares ISO-8859-1 | Decoded as declared |
| kantei.go.jp (Japanese PM's office) | Served as application/octet-stream. guids are positions (item_1 … item_25): tomorrow's item_1 is a different article | Detects the feed from its content. Identifies an item by guid and link, so a new item_1 is still new |
| abc.es | Lists the same article 20 times: one link for all of them, and the guid written both with and without a trailing slash | A trailing slash does not make a new item, so it is returned once and charged once. Items that really differ are still kept apart |
| A feed that stops mid-way | The server closes the connection, or a gzip body cannot be unpacked to the end | The item that was cut off is dropped, never returned and never charged. A free row says the body ended early |
| b.hatena.ne.jp | Every Japanese character in titles written as a hex entity (中) | Decoded |
| gov.uk | Double-encoded summaries (UK&#39;s) | UK's |
| blog.cloudflare.com, news.ycombinator.com | The page advertises the feed with a relative link (/rss/, rss) | Resolved against the page |
| YouTube channel pages | The feed link sits in <body>, not <head> | Found anyway |
| NPR podcast | 2.1 MB, 355 episodes in one feed | All read. Size limit is adjustable, and a feed cut at the limit returns only complete items |
| Most news feeds | Dates as Fri, 11 Sep 2026 13:00:00 GMT, 11 Sep 2026 19:00:00 +0900, 2026-09-12T00:00:00+09:00 | Converted to UTC |
We also ran the same 16 feeds and 10 website URLs through a second, independent XML parser. Item counts,
links and titles matched on every feed we could compare. The check lives in verify/crosscheck.mjs, so you
can run it again.
Dates are never guessed
publishedAt/updatedAthold a UTC instant only when the feed states a time zone.- A time with no zone (
2026-09-11 10:00) goes topublishedLocal/updatedLocalexactly as written. It is not treated as UTC, and it is not converted with the server's clock. - Abbreviations that mean more than one zone (
IST,BST) are treated as unknown. - The raw text is always kept in
published/updated.
Monitoring mode: only new items
Turn on Monitoring mode and the Actor remembers the items it returned for each feed.
- The first run returns everything and remembers it.
- Later runs return only items that were not returned before.
- A quiet day returns a free row that says
no-new-since-last-run. Nothing is charged. This is kept separate fromno-results, which means the feed really lists nothing. - Only items that were actually returned are remembered. If a run stops at a limit, the rest arrive on the next run.
- The memory is kept per feed and per filter setting, so two watches on the same feed with different keywords do not affect each other.
- The memory holds the last 5,000 items per feed and filter setting. A feed that publishes more than 5,000 items between two runs can return an older item again.
What comes back
| Field | What it is |
|---|---|
title, link | The item's title (plain text) and its absolute URL |
publishedAt, updatedAt | UTC instant, only when the feed states a time zone |
publishedLocal, updatedLocal | The time as written, when the feed gives no zone |
published, updated | The raw date text from the feed |
author, authors | Author names. Email addresses are removed (RSS writes authors as email (Name)) |
summary | The description / summary as plain text |
contentText | The full content as plain text, when the feed carries it (content:encoded, Atom content, JSON Feed content_html / content_text) |
contentHtml | The same content as HTML, only with includeContentHtml. Relative links and images are made absolute |
hasFullContent | Whether the feed carried full content for this item |
categories | Categories, tags, dc:subject |
imageUrl | media:thumbnail, an image media:content or enclosure, or itunes:image. Only images the feed itself names |
enclosureUrl, enclosureType, enclosureLength, enclosures | Podcast audio and other attachments. A stated length of 0 means unknown and comes back as null |
durationSeconds | From itunes:duration or JSON Feed attachments |
commentsUrl, externalUrl | RSS comments, JSON Feed external_url |
guid, guidIsPermaLink, itemKey | The feed's own id, and the key this Actor uses to recognise the item (guid + link) |
position, feedItemCount | The item's place in the feed, and how many items the feed lists |
feedTitle, feedLink, feedLanguage, feedType, feedEncoding | About the feed: rss-2.0, rss-1.0-rdf, atom, json-feed-1.1, …, and the encoding it was decoded with |
feedUrl, requestedUrl, foundVia | The feed actually read (after redirects), the URL you gave, and given / link-tag / common-path |
status, reason, httpStatus | ok, or why a URL produced nothing |
A field the feed does not state comes back as null. Nothing is filled in with a zero or a guessed date.
Input
| Field | Default | What it does |
|---|---|---|
urls | — | Feed URLs or website URLs. If this and urlsText are both empty, two example URLs are read and a free row says so |
urlsText | empty | The same list as a block to paste, one URL per line |
maxItemsPerFeed | 100 | Items per feed, in the feed's own order (newest first on almost every feed). 0 = all |
maxItems | 1000 | Items across the whole run. URLs not reached get a free not-looked-up row. Must be at least 1: 0 is not "no limit" here, and a free row says so if you send it |
discoverAllFeeds | off | From a website URL, read every advertised feed instead of the first one |
useCommonPaths | on | When a page advertises no feed, try /feed, /rss, /feed.xml, /rss.xml, /atom.xml, /index.xml, /feed.json |
includeContentHtml | off | Add contentHtml |
keywords, keywordMatch, excludeKeywords | empty / any / empty | Match against title, summary, content, categories and author |
publishedAfter | empty | YYYY-MM-DD. An item with no date is kept, because unknown is not the same as old |
timeoutSecs | 20 | Per request |
maxFeedSizeMb | 20 | Stop downloading a feed after this many MB. Only complete items are returned |
monitoringMode, resetMonitoringState | off | See Monitoring mode |
Pricing
Charged per item returned. The same item is never returned twice in one run, even when two feeds carry it or the
same feed is reached twice. Two feeds count as carrying the same article when the guid and link match (a trailing
slash is ignored) or when the title and publication time match. That second rule matters: Daring Fireball's Atom
feed and its JSON Feed carry the same 48 posts under completely different guids and links, so reading both with
discoverAllFeeds charges 48 items, not 96. A free row says how many items were folded that way.
Rows that explain why a URL produced nothing are not charged: bad address, blocked
(blocked-to-us, for example a Cloudflare "checking your browser" page), not a feed, no feed found, empty feed,
no match for the filters, nothing new in monitoring mode, an item already returned from another feed in the same
run, a body that ended in the middle, or not reached because of a limit.
What it fetches
Only the URLs you give. For a website URL, it also fetches the feed that page advertises and, unless
useCommonPaths is off, up to 14 common feed locations: the seven names in the page's own folder and the same seven
at the site root. It does not follow links or crawl a site.
robots.txt is not read or obeyed. This Actor fetches only the URLs you ask for, the way a feed reader does (Google documents the same approach for its Feedfetcher).
Addresses inside a private network are refused, before and after a redirect: localhost, 127.0.0.1, 10.x,
172.16-31.x, 192.168.x and the cloud metadata address 169.254.169.254. If you put a user name and password in a
URL (https://user:pw@example.com/feed), they are used to fetch the feed but are never written into feedUrl,
requestedUrl or the log.
Notes
- Character encoding comes from the byte-order mark, then the document's own declaration, then the HTTP header, then
UTF-8. When the declaration and the header disagree, the declaration wins. The exception is valid UTF-8 bytes
where either side says UTF-8, because a common server default adds
charset=ISO-8859-1to UTF-8 feeds. - gzip is detected from the first two bytes of the file, not from the
.gzin the name. - Only
httpandhttpsare accepted.feed://addresses are read ashttp://. - Paged feeds (RFC 5005
rel="next") are not followed. A run returns what the feed currently lists.