# RSS Change Monitor: Competitor Blog & News Alerts (`singletonops/public-rss-change-monitor`) Actor

Monitor public RSS and Atom feeds, such as a competitor's blog, newsroom or changelog, and get only the new items since the last run: title, link, published date and summary. Optional webhook for Slack, Zapier or Make. Lightweight HTTP, no browser, no login.

- **URL**: https://apify.com/singletonops/public-rss-change-monitor.md
- **Developed by:** [SingletonOps](https://apify.com/singletonops) (community)
- **Categories:** Marketing, SEO tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## 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

## Public RSS Change Monitor

Monitor **public** RSS and Atom feeds and get notified only when **new items** appear. Perfect for marketers, researchers, and ops teams who want cheap recurring feed watches without scraping login walls.

[![Apify Actor](https://img.shields.io/badge/apify-actor-blue)](https://apify.com)

***

### What does Public RSS Change Monitor do?

This Actor:

1. Fetches one or more public RSS/Atom feed URLs you provide
2. Normalizes each entry to `title`, `link`, `published`, and `summary`
3. Compares items against the last run’s state (stored in the default key-value store under `seen-state`)
4. Writes **only new items** to the default dataset
5. Optionally POSTs a JSON summary to your webhook URL when something new is found

Schedule it on Apify (e.g. every 15–60 minutes) for continuous monitoring with predictable compute cost.

***

### Why use this Actor?

| Benefit | Detail |
| --- | --- |
| Low legal risk | Public feeds only — no logins, paywalls, or authenticated APIs |
| Recurring value | Change detection across runs (state persisted in KVS) |
| Cheap compute | Lightweight HTTP + XML parse — no browser |
| Integrations | Optional webhook, plus Apify dataset/API exports to Zapier, Make, Slack, etc. |

***

### Input

| Field | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `feedUrls` | string\[] | ✅ | — | Public RSS/Atom feed URLs |
| `maxItemsPerFeed` | integer | ❌ | `50` | Max items read per feed (1–500) |
| `webhookUrl` | string | ❌ | — | HTTPS URL to POST when new items exist |
| `webhookSecretHeader` | string | ❌ | — | Value sent as `X-Webhook-Secret` (you supply it) |

#### Example input

```json
{
  "feedUrls": [
    "https://www.nasa.gov/news-release/feed/",
    "https://feeds.bbci.co.uk/news/rss.xml"
  ],
  "maxItemsPerFeed": 50,
  "webhookUrl": "https://example.com/hooks/rss-new",
  "webhookSecretHeader": "your-own-shared-secret"
}
```

> **Webhook secret:** Provide your own value. The Actor never generates secrets. When set, it is sent only as the `X-Webhook-Secret` HTTP header so your endpoint can verify the request.

***

### Output

#### Dataset (new items only)

Each dataset row is one newly detected feed entry:

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Stable ID from guid / id / link |
| `feedUrl` | string | Source feed URL |
| `title` | string | Entry title |
| `link` | string | Entry URL |
| `published` | string | null | Publish time from the feed |
| `summary` | string | null | Plain-text snippet (HTML stripped) |
| `detectedAt` | string | When this run marked the item as new (ISO-8601) |

#### Key-value store

| Key | Contents |
| --- | --- |
| `seen-state` | JSON map of `feedUrl → string[]` of previously seen item IDs |

On the **first run**, every item within `maxItemsPerFeed` is treated as new and written to the dataset. Subsequent runs emit only items not already in `seen-state`.

#### Webhook payload (when configured and new items exist)

```json
{
  "actor": "public-rss-change-monitor",
  "detectedAt": "2026-10-06T23:30:00.000Z",
  "newItemCount": 3,
  "feeds": [
    { "feedUrl": "https://www.nasa.gov/news-release/feed/", "fetched": 20, "newCount": 2 }
  ],
  "items": [
    {
      "id": "...",
      "feedUrl": "https://www.nasa.gov/news-release/feed/",
      "title": "...",
      "link": "...",
      "published": "..."
    }
  ]
}
```

***

### How to use

1. Open the Actor on Apify Store and click **Try for free**
2. Paste your public feed URLs into **Feed URLs**
3. (Optional) Add a webhook URL and your own secret header value
4. Click **Start**, or create a **Schedule** for recurring runs
5. Download results from the **Dataset** tab or call the Apify API

#### Local development

```bash
cd public-rss-change-monitor
## Edit storage/key_value_stores/default/INPUT.json
apify run
## Inspect storage/datasets/default/
```

***

### Pricing suggestion

For the Apify Store listing, consider one of:

- **Rental** — monthly rental for teams that schedule many feeds
- **Pay-per-event** — charge per feed checked and/or per new item emitted (good for light users)

Compute usage stays low (HTTP fetch + parse). Exact pricing can be tuned after measuring platform run costs.

***

### Legal & acceptable use

- **Public RSS/Atom feeds only.** Do not use this Actor on feeds that require login, cookies, API keys, or other authentication.
- Respect publisher terms of service and robots/rate-limit policies. Prefer reasonable schedules (e.g. every 15+ minutes) rather than aggressive polling.
- You are responsible for how you use the output (attribution, redistribution, downstream automation).
- This Actor does not bypass paywalls or scrape HTML article bodies beyond what the feed already publishes.

***

### Limitations

- Feeds that omit stable `guid`/`id` may fall back to `link` or `title|date`; duplicates can appear if those fields change.
- Very large feeds are truncated to `maxItemsPerFeed` (default 50).
- First run seeds state with current items — expect a burst of “new” rows once.
- Feed fetch failures are logged per URL; other feeds still process.

***

### Changelog

#### 0.1

- Initial release: multi-feed monitoring, KVS `seen-state`, dataset output, optional webhook

***

### Support

Open an issue on the Actor’s Apify page or contact the author through Apify Console messaging.

# Actor input Schema

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

List of public RSS or Atom feed URLs to monitor. Private or login-walled feeds are not supported.

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

Maximum number of items to read from each feed (newest first). Used both for change detection and to bound storage of seen IDs.

## `webhookUrl` (type: `string`):

Optional HTTPS endpoint that receives a JSON POST when new items are found. Payload includes newItemCount, feed summaries, and item stubs (id, title, link, published).

## `webhookSecretHeader` (type: `string`):

Optional shared secret you supply. When set, the Actor sends it as the X-Webhook-Secret request header so your endpoint can verify the caller. Store this value yourself — the Actor does not generate secrets.

## Actor input object example

```json
{
  "feedUrls": [
    "https://www.nasa.gov/news-release/feed/",
    "https://feeds.bbci.co.uk/news/rss.xml"
  ],
  "maxItemsPerFeed": 50
}
```

# Actor output Schema

## `newItems` (type: `string`):

Dataset of newly detected RSS/Atom items (title, link, published, summary).

## `seenState` (type: `string`):

Persisted per-feed item IDs used for change detection across runs.

# 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": [
        "https://www.nasa.gov/news-release/feed/",
        "https://feeds.bbci.co.uk/news/rss.xml"
    ],
    "webhookUrl": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("singletonops/public-rss-change-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 = {
    "feedUrls": [
        "https://www.nasa.gov/news-release/feed/",
        "https://feeds.bbci.co.uk/news/rss.xml",
    ],
    "webhookUrl": "",
}

# Run the Actor and wait for it to finish
run = client.actor("singletonops/public-rss-change-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 '{
  "feedUrls": [
    "https://www.nasa.gov/news-release/feed/",
    "https://feeds.bbci.co.uk/news/rss.xml"
  ],
  "webhookUrl": ""
}' |
apify call singletonops/public-rss-change-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,singletonops/public-rss-change-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/nrTlVkbwUD4Dx22pm/builds/qeM2URagXAQenWTxY/openapi.json
