# RSS Feed & Sitemap Monitor — New Items Only (`victorix/rss-sitemap-monitor`) Actor

Monitor RSS, Atom and JSON feeds, XML and news sitemaps and websites for new posts and pages. Give feed or sitemap URLs or a site's address, and optional keywords for alerts; get one row per item new since the last run: title, link, date, source and the feed's own summary, never the article body.

- **URL**: https://apify.com/victorix/rss-sitemap-monitor.md
- **Developed by:** [Victorix](https://apify.com/victorix) (community)
- **Categories:** News, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.54 / 1,000 new 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

### What is RSS Feed & Sitemap Monitor?

**RSS Feed & Sitemap Monitor — New Items Only** is an RSS feed monitor and sitemap monitor for PR, marketing and SEO teams, automation builders and developers: give it RSS, Atom or JSON feeds, XML sitemaps or a website's address, and each run returns only what is new since the last one, one row per new post or page with its title, link, published date, the feed it came from and the feed's own short summary, never the article text. Measured live on 2026-09-24 on 191 real feeds, sitemaps and home pages, it returned items from **157 of the 177** still online and reachable (**88.7 %**; 85.9 % if a sitemap index read without its newest pages counts as a miss), and two later runs that day delivered no item twice.

#### Use cases

- **RSS feed alerts in Slack, Discord, Telegram or e-mail:** PR, communications and media-monitoring teams follow competitors', regulators' and customers' newsrooms and press releases, with keyword alerts, without checking each site by hand.
- **Keyword alerts for the sites you choose,** a Google Alerts alternative: only the new items that mention your topics come back.
- **Sitemap monitoring:** marketing and SEO teams track competitors' blogs and sitemaps for new posts and new pages, including sites without a feed.
- **Automations in n8n, Make or Zapier:** one clean row per new article to post to Slack, Discord, Telegram or e-mail, or to add to a spreadsheet or a newsletter draft.
- **A dated log for researchers and analysts** of what a set of publishers put out, week by week.
- **RSS to JSON for developers and AI agents:** "what is new on these sites since yesterday" as JSON rows, without writing a feed parser and a de-duplication store.

#### What you get

One row per new item: `title`, `link`, `publishedAt` in UTC, the feed's own `summary` (at most 300 characters), `feedUrl` and `format` (RSS, Atom, RSS 1.0, JSON Feed, sitemap or news sitemap), as JSON, CSV, Excel, XML or HTML.

**Price:** $0.0315 per run on every tier plus $0.90 per 1,000 new items at Bronze ($1.035 on the Free tier); unchanged, unreadable and refused sources add nothing to the run fee.

**Main limit:** it returns only what feeds and sitemaps publish: never the article text or author names, and a site with neither, a bot wall or a robots.txt refusal ends as a free row.

### What data can you get from RSS feeds and sitemaps?

The Actor reads what feeds and sitemaps publish for machines to read and returns one row per new item, in the same fields whatever the format.

- **New items only:** the Actor remembers what each source already delivered, so a scheduled run gives you the delta, not the whole feed again.
- **Keyword alerts:** name words or phrases, and only the new items that mention them come back (and are charged).
- **Paste a site, not a feed URL:** give a site's address and the Actor finds its feed; give a sitemap index and it reads the child sitemaps most likely to hold its new pages.
- **Polite by design:** when the feed supports it, it asks "has anything changed?" with the ETag and Last-Modified the feed sent last time, and it reads the site's robots.txt before any request.
- **Every common format:** RSS 2.0, Atom 1.0, RSS 1.0 (RDF), JSON Feed 1.0 and 1.1, XML sitemaps (also `.xml.gz`), sitemap indexes and Google news sitemaps, detected from the document itself.
- **Headlines, not articles:** the feed's own summary, cut to 300 characters; the article body and any author name are never copied.
- **Empty where the source is silent:** a plain sitemap entry has no title or summary, and an item the source does not date has a null `publishedAt`; the row is still a new item.
- **A small fee per run, then pay per new item:** each run costs $0.0315, however many sources it checks, and each new item $0.0009; an unchanged feed, a feed that could not be read and a refused entry add nothing.

#### RSS feed monitoring, keyword alerts and sitemap monitoring in one Actor

Use it as an **RSS feed monitor** for newsrooms, blogs, release notes and regulators; as a **keyword alert** that reports only the new items mentioning your topics; or as a **sitemap monitor** that reports the new pages a site publishes, including sites without a feed. News sitemaps (Google's format) and sitemap indexes are read too. The rows are plain JSON, so the same run serves a Slack or e-mail alert through n8n, Make or Zapier, a Google Sheet, or your own code as an RSS-to-JSON API with the de-duplication already done.

### How to monitor RSS feeds and sitemaps for new items

1. Open the Actor in Apify Console and press **Try for free**.
2. In **Feeds and sitemaps**, list your sources, one per line — the prefilled NASA feed shows the shape. A site's address is enough when it has a feed; many sites list their sitemaps in `/robots.txt`. To be told only about some topics, add them under **Keywords**.
3. Leave **Monitor name** as `default` and **Maximum new items per source** at 20 for a first run.
4. Press **Start**. The run ends with a one-line summary in its status message; the first run returns up to 20 items per source.
5. Open the **Output** tab: the **New items** view shows one line per item. Export the rows as JSON, CSV, Excel, XML or HTML.
6. Save the input as a **task** and add a **schedule** (hourly, daily): each scheduled run returns only what appeared since the one before, and a quiet day costs only the run fee (see the cost section below).
7. For alerts, connect the task to Slack, Discord, Telegram or e-mail through n8n, Make or Zapier (see Integrations): forward each `ok` row, and every new item arrives as one message while a run with nothing new sends none.
8. To run it from your own code instead, copy the ready-made call from the Actor's **API** tab (see Integrations) and read the same rows from the run's default dataset.
9. To let an AI agent use it, add it to Claude, Claude Code, Cursor or any MCP client as a single-purpose connector: `https://mcp.apify.com/?telemetry-enabled=false&tools=victorix/rss-sitemap-monitor`. It loads just this one Actor as a direct tool, so your agent skips the Actor search and uses fewer tokens; new Apify accounts include $5 of monthly usage.

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

Pay per event, two events. Every run pays a run fee of $0.0315 per run when it starts, however many sources it checks and whether or not anything is new: the Actor charges it as its own `start` event, once per run, before it reads any source. A run that moves to another server, or that you resurrect, does not pay it again, and a maximum total charge too small for it reads nothing and ends with one free `limit-reached` row. Then one `result` event per `ok` row, that is per new item. Rows with `no-new-items`, `invalid-input`, `source-error` or `limit-reached` are free: a source that has not changed, could not be read or was refused adds nothing to the run fee. Platform usage is included in both prices; there is no other charge.

| Event | Charged when | Price (Bronze) | Per 1,000 |
|---|---|---|---|
| `start` (run fee) | a run starts, once per run | $0.0315 per run | $31.50 per 1,000 runs |
| `result` | a row has status `ok` (a new item) | $0.0009 per new item | $0.90 per 1,000 new items |

Worked examples: a daily schedule over 10 news feeds; on the first run each returns its 20 newest items: 200 `result` events and one run fee, $0.18 + $0.0315 = $0.21; on a typical later day 6 feeds have 5 new items each and 4 have nothing new → 30 `result` events, 4 free rows and the run fee, $0.06; a month of daily runs pays $0.95 in run fees. An hourly RSS feed monitor of 20 news feeds that publish 2 new items an hour between them → 720 runs and 1,440 `result` events a month: $22.68 in run fees + $1.30 for the items = $23.98; with keywords, only the matching items are charged, and the run fee stays the same. Run fees add up with the schedule, not with the number of sources, so one run over all your feeds costs less than one run per feed. The table quotes the **Bronze** price, which is the list price; **Silver** buyers pay $0.702 and **Gold** buyers $0.54 per 1,000 new items, and so do **Platinum** and **Diamond** buyers; the **Free** tier pays $1.035, and the run fee is $0.0315 on every tier. Apify's pricing page puts the Free plan on the Free tier, Starter on Bronze, Scale on Silver and Business on Gold; Platinum and Diamond are Apify's enterprise tiers. The free plan's $5 of monthly platform credit covers, for example, 30 daily runs ($0.95 in run fees) and about 3,920 new items at the free tier's price.

The Actor never delivers more items than your maximum total charge can pay for. When the limit is reached it stops and writes one `limit-reached` row naming the source it stopped at and how many entries are left, that one included; the items it did not deliver are **not** marked as seen, so the next run returns them. An item whose feed leaves a field empty (no date, no summary) is still a new item and is charged; the null in that field says what is missing.

### How does it compare with other ways to monitor RSS feeds?

| Option | What it watches | What you get | How you pay | Limits |
|---|---|---|---|---|
| **This Actor** | the RSS, Atom and JSON feeds, XML sitemaps and site addresses you list, up to 100 a run | one JSON row per item new since the last run, with an optional keyword filter: title, link, date, source and the feed's own summary | $0.0315 a run plus $0.90 per 1,000 new items at Bronze; unchanged and unreadable sources add nothing | no article text or author names; a site needs a feed or a sitemap |
| Google Alerts | Google's index, for the words you give | alerts by e-mail or RSS, as they happen, daily or weekly | free | you cannot choose the sites it watches |
| Slack's RSS app | the feeds you add to Slack | the items newer than its last check, posted in Slack | free | Slack only |
| A reader app | the feeds you subscribe to | a reading list, with keyword rules, alerts or an API in some plans | free tiers and monthly plans | a feed count per plan |
| A feed reader that returns every item | the RSS and Atom feeds you list | every item still in each feed, on every run, often with the full article text | per item returned plus a run fee: about $2,050 a month for an hourly schedule over 102 feeds at Bronze, against about $143 here | you remove the repeats yourself |

The last row's figures are our measurement of 2026-09-24: 102 feeds that published about 186 new items an hour at the time measured, billed at the leading feed reader's Bronze prices that day, at its default of 50 items a feed (its prices were the same on 2026-09-29), and at this Actor's prices above. The other rows describe each service as its own pages did on 2026-09-24.

### Input

| Field | Type | Default | Example |
|---|---|---|---|
| `sources` | array of URLs (required, max 100, unique) | — | `["https://www.nasa.gov/feed/", "https://blog.rust-lang.org/feed.xml"]` |
| `keywords` | array of words or phrases (optional, max 50, each up to 100 characters) | — | `["merger", "interest rate"]` |
| `monitorName` | string, letters, digits, `-` and `_`, up to 40 | `default` | `competitor-newsrooms` |
| `maxItemsPerSource` | integer 1–1000 | `20` | `50` |
| `since` | ISO 8601 date or date-time (optional) | — | `2026-09-01` |

A **source** is the URL of a feed or a sitemap, or a site's address; the Actor tells them apart by the document itself, so you do not say which is which. A URL without `https://` is read as https. A **sitemap index** (a sitemap of sitemaps) is read through the three child sitemaps most likely to hold its new pages (see Supported feed formats, sitemaps and limits), and their items come back under the index; an index whose children are named by section or split by a hash is better watched through the child sitemap you need, given as the source. A **web page** is searched for its feed: first the feeds it names in its `<link rel="alternate">` tags, then links on the page to an address ending in `feed`, `rss` or `atom` on the same site, then the common addresses `/feed`, `/rss`, `/feed.xml`, `/rss.xml`, `/atom.xml`, `/index.xml`, `/feed.atom` and `/feed.json` on its site; the first one that is a feed becomes the source, and later runs ask that feed directly. **`keywords`** narrows what comes back: an item is returned only when one of the words or phrases appears in its title, its summary or the words of its link (a sitemap entry has only its link), as a whole word, in any case; `rate cut` matches "Rate  Cut" but `merger` does not match "mergers". Items the keywords leave out are free and are not remembered: they are checked again whenever their feed or sitemap changes (one that answers "not modified" is not read again until then), so after you change the keywords, one that now matches is delivered at the source's next full read (for most sources, its next change), as long as it is dated no more than 72 hours before the newest item already delivered (see Supported feed formats, sitemaps and limits). Leave it empty to get every new item. **`monitorName`** is the name under which the Actor remembers each source's delivered items: every run with the same name returns only what is new since the last of them, so give each schedule that watches its own set of sources its own name, or a fresh name to start over. **`maxItemsPerSource`** caps how many new items one source returns per run, the newest first. On every run, not only the first, the new items over the cap are skipped, not kept for later: a first read of a large sitemap can list thousands, and a busy source can list more new items between two runs than the cap (when we measured it on 24 September 2026, PR Newswire's news sitemap listed 201 in 80 minutes: a cap of 20 returned the newest 20 and skipped the other 181 for good). For a busy source, raise the cap or run the schedule more often. **`since`** is a floor on every run: items dated before it are never returned, the 72-hour allowance for late items (see Supported feed formats, sitemaps and limits) included. A source the Actor cannot read as a URL gets one free `invalid-input` row and is never requested. An input the Actor rejects produces `invalid-input` rows and a failed run that charges no `result` event, only the run fee (see the cost section).

### Output: one row per new item

One row per new item, newest first within each source, sources in the order you listed them. A source with nothing new gives one row saying so.

```json
{
  "input": "https://www.nasa.gov/feed/",
  "status": "ok",
  "source": { "url": "https://www.nasa.gov/feed/", "checkedAt": "2026-09-23T12:00:00.000Z" },
  "error": null,
  "result": {
    "title": "NASA-Funded Research Finds Complex Life Defying Record Heat",
    "link": "https://science.nasa.gov/science-research/planetary-science/nasa-funded-research-finds-complex-life-defying-record-heat/",
    "publishedAt": "2026-09-22T17:33:10.000Z",
    "summary": "Lee esta historia en español aquí. NASA-supported scientists have discovered an organism that lives at extreme temperatures previously thought impossible for complex life…",
    "feedUrl": "https://www.nasa.gov/feed/",
    "format": "rss",
    "fetchedAt": "2026-09-23T12:00:00.000Z"
  }
}
```

| Field | Type | Meaning |
|---|---|---|
| `input` | string | The source as you entered it |
| `status` | `ok` · `no-new-items` · `invalid-input` · `source-error` · `limit-reached` | See the cost section: only `ok` is charged |
| `source` | `{ url, checkedAt }` | The URL that answered (after redirects), and when |
| `error` | `null` or `{ code, message }` | Why there is no item: `same-feed` (on a free `no-new-items` row; see Supported feed formats, sitemaps and limits), `robots-disallowed`, `robots-unreachable`, `source-unreachable`, `blocked`, `not-a-feed`, `too-large`, `too-many-entries`, `too-many-redirects`, `http-<status>`, `not-fetched`, `invalid-input`, `limit-reached`, and `source-error` for any other failure, such as a read that timed out |
| `result` | object or `null` | One new item, for `ok` rows |

The `result` fields: `title` (plain text; null for a plain sitemap entry, which has none, and for a feed item that has none, such as a micro-post in a JSON Feed, whose body the Actor does not read, so such an item comes back with its link and date); `link` (absolute, with `utm_*` and similar tracking parameters and the `#fragment` removed); `publishedAt` in UTC (from `pubDate`, `published`, `dc:date`, `date_published`, `news:publication_date` or `lastmod`; null when the source gives none); `summary` (the feed's own description as plain text, at most 300 characters; null when there is none, and always for sitemaps); `feedUrl` (the feed or sitemap that listed the item: the feed found on a web page you gave, or the index you gave for an item from one of its child sitemaps); `format` (`rss`, `atom`, `rdf`, `json-feed`, `sitemap` or `news-sitemap`); `fetchedAt`. The dataset schema also lists `not-found`, part of the contract all our Actors share; this Actor never produces it — a feed that is gone is a free `source-error`.

### Supported feed formats, sitemaps and limits

| You give | The Actor reads | Each row carries |
|---|---|---|
| A feed: RSS 2.0, Atom 1.0, RSS 1.0 (RDF), JSON Feed 1.0 or 1.1 | the feed itself | the title, link and date and the feed's own summary, where the feed gives them |
| An XML sitemap, also `.xml.gz` | the sitemap itself | the link, and its `lastmod` date when it has one; no title or summary |
| A Google news sitemap | the sitemap itself | the link, the title and the publication date |
| A sitemap index | at most 3 of its child sitemaps, one nested level down, 6 documents at most | as its child sitemaps |
| A site's web page | the feed its `<link>` tags name or the page links to, else one at 8 common addresses | as that feed |

- Up to 100 sources and at most 1,000 new items per source per run (`maxItemsPerSource`). Reading stops at 20 MB (unpacked) per document and the source gives a free `too-large` row. A sitemap with more than 10,000 entries without a date, or sharing its newest date, gives a free `too-many-entries` row: the Actor could not remember them all, and a forgotten entry would come back as new and be charged again. A sitemap with more than 10,000 entries in the 72 hours before its newest item delivered (a large shop's nightly import, for example) still works, without the allowance for late items (below): the Actor remembers only its entries at the newest date, so an entry dated before that newest date is not delivered unless the site re-dates it later, and then it counts as new.
- **A sitemap index** is read through at most 3 of its child sitemaps, chosen by their dates where the dates tell them apart and by their names everywhere else. Children whose dates are separated by a gap of more than five minutes are read newest first. Children whose dates follow each other with no gap of more than five minutes were written by one regeneration of the index, so their dates say nothing about which holds the new pages, and they are chosen by their names, as are the children of an index that dates none: first both ends of the first numbered series it lists (`posts-post-1` and `posts-post-8`, `sitemap-0` and `sitemap-1210000`), because sites number their pages either way (WordPress core puts its newest posts on the last page, others on the first); then the children named by a date, the newest first (`sitemap-2026-9`); then both ends of the next series; and, when the names carry neither a number nor a date, the first two and the last listed. So the same children are read from run to run while only their dates move, as long as a regeneration leaves no gap of more than five minutes between the dates it writes. A date that every child of one regeneration carries in its address (a directory above them all), or every undated child, is ignored. A child that is itself an index is read the same way one level down, never deeper, and at most 6 child documents are read per index. The index and its children are read in full on every run (a child can change while the index does not), so the ETag and Last-Modified check does not apply to them. What an index delivered is remembered across the children read, up to 11,000 items per source, so a child that fails in one run, or is no longer among the three read, does not bring its items back as new later; beyond 11,000 the oldest are forgotten and can come back as new, and its items dated more than 72 hours before the newest item delivered in the meantime are not delivered either. Children named by section (`/page/`, `/research/`) or split by a hash (`sitemap-0` to `sitemap-8` with no order) give no sign of where new pages are, so three of them are a guess: for such an index, or any part of a site these choices miss, add the child sitemap you need as its own source.
- **A web page** is searched for its feed as Input describes: at most 2 of the feeds its `<link>` tags name, at most 2 feed-looking links from the page, then the 8 common addresses, each checked against robots.txt first. A page that names no feed and has none at those addresses gives a free `not-a-feed` row saying it is a web page; a bot-check page gives a free `blocked` row and nothing is looked for behind it, and a common address that answers 401, 403 or 429 ends the search as a free row too. The feed found is remembered and asked directly on the next runs; if it stops answering as a feed, the page is searched again.
- **One feed reached from two of your entries** (a site's address and the feed it leads to, or two pages of one site that name the same feed) is requested once per run (a feed over 2 MB, or one read again after the run moved to another server, may be requested twice) and charged once: its new items are on the rows of the entry listed first, and the other entry gets one free `no-new-items` row whose error, `same-feed`, names that entry. Both entries then remember what was delivered, even when your charge limit stopped the run inside the first entry's items, so swapping the two or removing one brings nothing back as new, once each entry has been read at least once; two entries added together whose first run the charge limit stops before the second is read have not met yet. An entry you remove and add back later delivers what arrived while it was away, as its own feed would. An entry you add in front of a feed you already watch is new, so its first run delivers the feed's current items as any new source does (once, not twice), and the feed may be requested twice in that run. Only a run that lists both knows they meet: two tasks or two monitor names that each watch one of them keep separate memories, and an item is delivered, and charged, once in each. A site's feed and its sitemap, or a sitemap index and one of its child sitemaps, are two different documents, not one feed reached twice: each is watched and charged on its own, so a post listed in both is two rows. Two addresses that only redirect to one feed are charged once too, though each may be requested.
- **The data is as fresh as the source:** each run reads every source live; nothing is cached except the per-source memory of what was delivered (below). A feed usually lists only its latest 10–50 items, so run the monitor more often than the feed's window turns over, or older items slip past between two runs.
- **What "new" means:** an item is new when its identity (the RSS `guid`, the Atom `id`, the RSS 1.0 `rdf:about`, the JSON Feed `id`, else the link) was not in the source when this `monitorName` last finished reading it (an item a run's charge limit cut off arrives at the next run; see the cost section), and it is dated no more than 72 hours before the newest item already delivered and not before your `since`. The 72 hours are for items that reach a feed or sitemap after their date: a story that enters a "latest" feed hours after it was published, a front page that promotes this morning's articles, a product that enters a shop's sitemap with the night's import date. When we measured news feeds and sitemaps on 24 September 2026, 24 of 25 such late stories were within 72 hours; an unseen item dated more than 72 hours before the newest one delivered (a backdated post, a front page bringing back an old story) is not new. Only a new identity counts as new: an item a site edits or re-dates under the same guid or link is not delivered again, whether it was delivered or skipped over `maxItemsPerSource` (see Input), while one republished under a new link is. For that the Actor keeps the identity of every item its source lists dated from 72 hours before the newest item delivered on, and keeps it for as long as the source lists the item, up to 11,000 per source; an item it first saw dated more than 72 hours before the newest one delivered, which its site re-dates later (an old page edited), counts as new once. The same article in two of your feeds is one row per feed.
- **What the Actor keeps between runs:** for each source and monitor name, the ETag, the Last-Modified date, the newest publication date delivered, the feed found on a web page, and short hashes of the entries that could still come back as new (those without a date, or dated within the 72 hours before the newest item delivered) and of the delivered items the source still lists, with the date from which those hashes are complete, in a named key-value store in your Apify account, `rss-sitemap-monitor-watch-v1`. A source's record is written only when something in it changes (an item delivered, new validators from the site, a newly found feed), so a check that finds nothing new and gets the same validators writes nothing. An entry whose feed another entry of the run reaches (above) keeps a copy of that entry's record. A named store is kept until you delete it and is billed as storage like any other (a few kilobytes for a feed, at most about 215 KB for a sitemap with thousands of undated or recent entries); delete it, or change `monitorName`, to start over. If the store cannot be opened, the run still works, counts every item as new and says so in its status message.
- Politeness: up to five sources on different sites are read side by side, but each site gets one request at a time and at least a second between two of them, a 30-second timeout, two retries with backoff on a busy answer, `Retry-After` honoured up to 30 seconds (a site that asks for a longer pause, such as a feed whose origin is down behind Cloudflare, gets a free error row at once and is asked again next run, rather than holding the run for minutes), at most 5 redirects, each checked against its own site's robots.txt.

### Is monitoring RSS feeds legal?

Feeds and sitemaps are published for machines to read. The Actor honours each site's robots.txt, never passes a bot check or logs in, and copies only titles, links, dates and the feed's own short summary, never article bodies or author names. What you do with the items is governed by each publisher's terms (below).

The data is what **the feeds and sitemaps you name** publish for machines to read, or what the feed a site's page names publishes: the Actor reads a page only for its feed links and the common feed addresses, never its text, and follows no link to an article. It:

- **copies the feed's facts and its own short summary, never the article:** title, link, date and the feed's own summary cut to 300 characters; the article body (`content:encoded`, Atom `content`, JSON Feed `content_html` and `content_text`) is never read into a row, so nothing a publisher wrote beyond its own excerpt is reproduced;
- **leaves people out:** author names and by-lines (`dc:creator`, `author`, `authors`) are never copied; a person named in a headline or summary stays only as the publisher wrote it;
- **honours robots.txt** for every request (RFC 9309, for its own name `rss-sitemap-monitor`, else the rules for all robots); a site whose robots.txt disallows the path, or cannot be read, is not requested and gives a free row;
- **never passes a block:** a bot-check page, a CAPTCHA or a login is a free `source-error`, not something the Actor tries to get past; there is no proxy input and no login, and a URL carrying a user name or password is refused.

**The sources are yours to choose, and so are their terms.** A publisher's terms of use can limit what you may do with its feed, for example commercial reuse or text and data mining under Article 4 of the EU Directive on Copyright in the Digital Single Market; some publishers state such limits in comments in their robots.txt, which no program can read as rules. Check the terms of the sites you monitor before you republish or build a product on what they send.

Not affiliated with, sponsored or endorsed by any publisher whose feed or sitemap you monitor, by NASA or the Rust project, whose public feeds appear in the examples, by Google, whose news sitemap format the Actor reads and whose Alerts service this page compares it with, or by Slack, whose RSS app the comparison names.

Support: open an Issue on the Actor's Issues tab and you get a reply within 12 hours.

### Integrations: API, MCP, n8n, Make, Zapier, Slack and e-mail

- **API (RSS to JSON):** start a run with `POST https://api.apify.com/v2/acts/victorix~rss-sitemap-monitor/runs`, the JSON input as the body and your token in the `Authorization: Bearer <token>` header, never in the URL; then read the default dataset as JSON or CSV with the same header. The Actor's API tab in Console shows each call ready to copy.
- **AI agents:** the Actor is available to AI agents through Apify's MCP server, which can call any public Actor by name, so an agent can ask what is new on a list of sites; each tool call is one run, charged the run fee and one `result` event per new item.
- **Slack, Discord, Telegram and e-mail alerts (n8n, Make, Zapier):** use the Apify node, module or app, run or watch this Actor's task, pass `sources` as an array, and send each `ok` row on as a message; the same integrations add rows to Google Sheets or Airtable.
- **An n8n recipe:** the Apify node is a community node, `@apify/n8n-nodes-apify`, so install it first (Settings > Community Nodes on a self-hosted n8n; on n8n Cloud, from the nodes panel once verified community nodes are enabled). Choose Run an Actor and Get Dataset, pick this Actor and write each list from an earlier step into the Input JSON with `JSON.stringify`, for example `{"sources": {{ JSON.stringify($json.urls) }}, "keywords": {{ JSON.stringify($json.keywords) }}}`. Written as `{{ $json.urls }}` inside quotes or brackets, a list arrives as one text with its items joined by commas: Apify refuses that text with a message naming this fix, an entry holding several URLs is a free `invalid-input` row that says so, and a keyword holding several keywords stops the run before any source is read, which then pays only the run fee, as any input the Actor itself refuses does.
- **Clay:** Clay can run Apify Actors from a table, for example to check each account's newsroom feed on a schedule.
- **Schedules and webhooks:** save the input as a task, schedule it, and add a webhook on "run succeeded" to be told when new items arrive.

### More Actors from us

Every public Actor of ours is listed on our Apify profile: [apify.com/victorix](https://apify.com/victorix).

- **Product price & stock scraper** — prices, stock, SKU and brand from the product pages you list or from whole Shopify, WooCommerce and other shops, for competitor price monitoring: [apify.com/victorix/product-price-scraper](https://apify.com/victorix/product-price-scraper)

### FAQ

#### How do I get RSS feed alerts in Slack, Discord or by e-mail?

Save your input as a task and schedule it, then connect the task to Slack, Discord, Telegram or e-mail with n8n, Make or Zapier: their Apify integrations run or watch the task and send each `ok` row as a message. Only new items arrive, so a quiet hour sends nothing, and keywords narrow the alerts to the topics you follow.

#### How do I monitor a sitemap for new pages?

Put the site's sitemap into `sources`: `/sitemap.xml`, or the one its `/robots.txt` names. Each run returns only the URLs new since the last one, newest first by `lastmod`. From a sitemap index the Actor reads three child sitemaps, the ones most likely to hold new pages: the newest by date, else both ends of a numbered series (`posts-post-1` and the last page) and the newest month or day in the names (see Supported feed formats, sitemaps and limits). When the children are named by section or split by a hash, the names say nothing about where new pages are: add the child sitemap of the section you want as its own source, which is also how to watch one section of a big site.

#### How do I find a website's RSS feed?

Paste the site's address. The Actor looks for the feed the page names, then for feed links on the page, then at common addresses such as `/feed` and `/rss.xml`, and reads the first feed it finds; `feedUrl` and `source.url` show which. If the site has no feed, its row says so and costs nothing: try the sitemap its `/robots.txt` lists.

#### How do keyword alerts match?

A keyword matches as a whole word or phrase, in any case, in the title, summary or link words (`big-bank-merger-approved` contains `merger`). `merger` misses "mergers": add both. An item matching none is neither returned nor charged; it is checked again when its feed changes, so new keywords can deliver it then, if it is dated no more than 72 hours before the newest item delivered.

#### Can it replace Google Alerts?

For the sites you care about, yes. Google Alerts searches the web for your words; this Actor watches the feeds and sitemaps of the sites you name and returns every new item, or only those that mention your keywords, as rows you can schedule, filter and send anywhere. It does not search sites you have not listed.

#### How do I convert an RSS feed to JSON with an API?

Start a run through the Apify API with your feeds in `sources`, then read the run's dataset as JSON: one row per item with `title`, `link`, `publishedAt`, `summary`, `feedUrl` and `format`, whether the feed is RSS, Atom, RSS 1.0 or JSON Feed. Each run returns what is new since the last one under its `monitorName`; a fresh name starts over.

#### Can an AI agent use it as an RSS MCP server?

Yes. Add it to Claude, Claude Code, Cursor or any MCP client as a single-purpose connector through Apify's MCP server, `https://mcp.apify.com/?telemetry-enabled=false&tools=victorix/rss-sitemap-monitor`, and the agent can ask what is new on a list of sites. Each tool call is one run, charged the run fee and one `result` event per new item.

#### How long does a run take?

About 5 to 10 seconds for 20 feeds, and about a second for one feed alone; a sitemap index or a web page without a feed takes four to ten. Up to five sources on different sites are read side by side: in our test nine sources (eight feeds and a news sitemap) checked again took 2.3 seconds, and twelve mixed sources 10 to 12.

#### How much does it cost to monitor feeds every hour?

About $23.98 a month at the Bronze price for 20 news feeds that publish 2 new items an hour between them: 720 runs cost $22.68 in run fees and their 1,440 new items $1.30. You pay a run fee of $0.0315 per run (the `start` event) and one `result` event ($0.0009) per new item; a feed with nothing new adds nothing to the run fee. A daily schedule over the same feeds costs $0.95 in run fees plus the same $1.30. The cost section gives the prices per tier.

#### Why did a source answer `no-new-items`?

The source answered, and everything in it was already delivered under this `monitorName`, or the server said the feed had not changed since the last run; with a `same-feed` error, its feed was read for an earlier entry of the run (next question). The row is free and says when the source was checked. To receive everything again, run with a new `monitorName`, or delete the watch store (see Supported feed formats, sitemaps and limits).

#### Why did an entry answer `no-new-items` with a `same-feed` error?

That entry leads to a feed another entry of the same run reaches too, for example `https://css-tricks.com/` and `https://css-tricks.com/feed/`. The feed is read once, and its new items are on the rows of the entry listed first, whose number and address the message gives; you are not charged twice for them. Remove one of the two entries if you want one row per run instead of two.

#### Why did a row cost nothing?

Its status was `no-new-items`, `invalid-input`, `source-error` or `limit-reached`: nothing was new (or nothing new matched your keywords), the entry could not be read as a URL, the source could not be read or refused us, or your charge limit was reached. Beyond the run fee, each new item is what you pay for.

#### Why did an item I can see in the feed never arrive?

It was dated more than 72 hours before the newest item this monitor had already delivered (a backdated post, or a front page bringing back an old story), it was dated before your `since`, it did not match your `keywords`, it arrived together with more new items than `maxItemsPerSource` and was among the older ones skipped (next question), or it appeared and dropped out of the feed between two runs; from a sitemap index, it may sit in a child sitemap the Actor did not choose (see Supported feed formats, sitemaps and limits). An item that reaches the feed late but is dated less than 72 hours before the newest one delivered does arrive, at the next run.

#### What happens when a source publishes more than `maxItemsPerSource` items between two runs?

The run returns the newest ones up to `maxItemsPerSource` and skips the rest for good, on every run, not only the first: a skipped item is not returned later, even when its site re-dates it, unless it was dated more than 72 hours before the newest item delivered (see Supported feed formats, sitemaps and limits). When we measured it on 24 September 2026, PR Newswire's news sitemap listed 201 new items in 80 minutes, so a cap of 20 returned 20 of them. For a busy source, raise `maxItemsPerSource` (each item returned is a `result` event), or run the schedule more often so fewer items arrive between two runs.

#### Why is the summary empty?

The feed publishes no summary for that item (Atom feeds often carry only the full text, which the Actor does not copy), or the source is a sitemap, which has none. The row is still a new item and is charged: the null says what the source did not provide, and the link leads to the article itself.

#### Does it read the full article?

No. It returns the link, the title and the date, and at most the feed's own short summary, cut to 300 characters; it never opens the article page or copies the feed's full-text fields or author names. To analyse the articles themselves, pass the links to a crawler of your choice, within each publisher's terms.

#### Can I watch the same feed for two purposes?

Yes. Use two tasks with different `monitorName` values, for example one sending every new item to a spreadsheet and one with keywords for alerts. Each name keeps its own memory, so each task returns the new items since its own last run, and an item delivered to both is charged once in each.

### Changelog

- 0.3 (2026-10-06): an item whose address carries an XML character reference, as WordPress writes a custom post type's (`?post_type=press-release&#038;p=1052091`), is now told apart from the others: NASA's press releases had all been read as one item, so only the first was ever delivered. Items without such a reference keep their identity and are not delivered again after the update; an item with one that was listed in about the last 72 hours, such as the press release already delivered under the shared identity, may arrive, and be charged, once more. The input form now also says that on a plain sitemap only page addresses can match a keyword, that Maximum new items per source counts only the items your keywords match, and that new items your spending limit cuts off come in the next run, while those over the maximum are skipped.
- 0.3 (2026-10-06): a list sent as one text, its items joined by commas (what n8n sends for a list written inside quotes or brackets in the Apify node's Input JSON), no longer passes as one malformed value. A text given for `sources` or `keywords` is refused with a message that says how to send a list; an entry that holds several URLs is a free `invalid-input` row naming the fix, where it used to be read as one address and its other feeds never; and a keyword with a comma and no space after it is refused with the run, which pays only the run fee, where it used to match nothing and say nothing (a phrase such as Washington, D.C. keeps the space after its comma). The README's Integrations section has an n8n recipe.
- 0.3 (2026-09-29): the run fee is charged as the Actor's own `start` event, once per run, and a run that moves to another server or is resurrected does not pay it again; Node.js caps its heap at three quarters of the run's memory (the platform's image had allowed a 30 GB heap in a 256 MB run); a malformed page or sitemap index can no longer stall a run (their scans now take linear time: 12 ms instead of 148 s for a hostile sitemap index whose addresses run to 200,000 characters); this README reorganised for search.
- 0.3 (2026-09-24): sources on different sites are read side by side (each site still one request at a time, a second apart), so a run of many feeds takes a fraction of the time; a source's record is written only when it changes; items your keywords leave out are no longer remembered, so after a keyword change they can still arrive when their feed next changes, if they are dated no more than 72 hours before the newest item delivered; an item delivered earlier and re-dated by its site is no longer delivered again; a sitemap index's children are chosen by their names where their dates come from one regeneration or are missing (both ends of a numbered series, the newest month in the names), so a WordPress index's newest posts page is read and the choice stays put when only the dates move; a site asking for a pause longer than 30 seconds is no longer waited on (a free error row instead of a run held for five minutes), and two requests to one site now always start at least a second apart; an item that reaches its feed or sitemap late, dated up to 72 hours before the newest one delivered, is delivered instead of dropped (a story entering a "latest" feed hours after its date, a product entering a sitemap with the night's import date), and an item listed within those 72 hours is never delivered later, re-dated or not; one feed reached from two of your entries, such as a site's address and the feed it links, is read and charged once, on the entry listed first, and the other entry gets a free row naming it.
- 0.2 (2026-09-24): sitemap indexes are read through their newest child sitemaps (one nested level); a site's address is searched for its feed; JSON Feed 1.0 and 1.1; keyword alerts (`keywords`); news sitemaps under any namespace prefix; Drupal's feed dates; a web page is reported as a web page, not a bot check.
- 0.1 (2026-09-23): first version. RSS 2.0, Atom, RSS 1.0 and sitemaps (news sitemaps and `.xml.gz` included), new items since the last run per monitor name, conditional requests, robots.txt for every request.

# Actor input Schema

## `sources` (type: `array`):

One URL per line: an RSS 2.0, Atom 1.0, RSS 1.0 or JSON Feed, an XML sitemap or a Google news sitemap (.xml or .xml.gz), a sitemap index (the child sitemaps most likely to hold its new pages are read), or a site's web page (the feed it links, or one at a common address such as /feed, is read). Give up to 100 a run, each URL once, for example https://www.nasa.gov/feed/ or https://blog.rust-lang.org/feed.xml.

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

Only return new items whose title, summary or link contains one of these words or phrases, as a whole word, in any case; a plain sitemap has only links, so only page addresses can match. Give up to 50, each up to 100 characters, one per line, for example merger or interest rate; leave empty for every new item. Items left out are free and checked again when their feed changes, so after a keyword change they can still arrive if dated no more than 72 hours before the newest item delivered.

## `monitorName` (type: `string`):

What the run remembers is kept under this name, per source: runs with the same name only return what is new since the last of them. Use a different name for each schedule or task that watches the same sources separately, or a new name to start over. The name takes letters, digits, - and \_, up to 40 characters, for example competitor-newsrooms.

## `maxItemsPerSource` (type: `integer`):

The most new items one source returns in one run, the newest first: 1 to 1,000, 20 by default; with keywords, only matching items count. On every run, not only the first, new items over this number are skipped for good: a first read of a large sitemap can list thousands, and a busy news source can list hundreds between two runs, so raise it or run more often for a busy source. Combine with the run's spending limit to cap cost: items that limit cuts off come in the next run.

## `since` (type: `string`):

An ISO 8601 date or date-time, for example 2026-09-01 or 2026-09-01T08:00:00Z. Items dated before it are never returned, on the first run or any later one. Items without a date are not affected.

## Actor input object example

```json
{
  "sources": [
    "https://www.nasa.gov/feed/"
  ],
  "monitorName": "default",
  "maxItemsPerSource": 20
}
```

# Actor output Schema

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

All rows of this run: one envelope item per new item or per source without one (input, status, source, error, result).

# 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 = {
    "sources": [
        "https://www.nasa.gov/feed/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("victorix/rss-sitemap-monitor").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 = { "sources": ["https://www.nasa.gov/feed/"] }

# Run the Actor and wait for it to finish
run = client.actor("victorix/rss-sitemap-monitor").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 '{
  "sources": [
    "https://www.nasa.gov/feed/"
  ]
}' |
apify call victorix/rss-sitemap-monitor --silent --output-dataset

```

## MCP server setup

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

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/caXjrlGid3i50CYog/builds/Ea67MZJNmeji4jP0y/openapi.json
