# RSS News Monitor — Deduplication & Change Tracking (`longish_whistle/rss-news-dedup-change-monitor`) Actor

Turn RSS and Atom feeds into a filtered, deduplicated news list. Track new and edited headlines with source links and before/after evidence. JSON and CSV; no API key or full-article scraping.

- **URL**: https://apify.com/longish\_whistle/rss-news-dedup-change-monitor.md
- **Developed by:** [Tender Delta](https://apify.com/longish_whistle) (community)
- **Categories:**
- **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 delivereds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## RSS News Monitor — Deduplication & Change Tracking

**Build one clean research list from several feeds, without repeatedly paying for the same unchanged headlines.**

Read public RSS 2.0 and Atom 1.0 feeds, filter titles or categories by topic, deduplicate identical article URLs across feeds, and compare against a previous run. Every delivered item includes its source link, publication date when available, and source-feed provenance.

### What buyers can build

- A daily research queue from industry blogs and official announcements.
- A newsletter editor's shortlist with repeated URLs removed.
- A company-news or release-announcement watchlist connected to an existing workflow.

The Actor delivers headline metadata, not rewritten news or full articles. It does not contact anyone, send alerts by itself or publish your newsletter.

### Start with five headlines

```json
{"feeds":["https://www.nasa.gov/feed/"],"maxItems":5}
```

Five delivered items cost **$0.005**, plus the displayed Actor start charge. No source API key, browser or proxy subscription is required. Supply direct feed URLs; a normal website homepage is not auto-discovered.

To filter a topic, add keywords such as \["launch","research"]. Matching is case-insensitive across titles and categories; it is a deterministic substring filter, not AI relevance scoring. Optional publishedSince takes a UTC ISO date-time; entries with missing/invalid dates are excluded by that filter rather than guessed.

### Deduplication and change tracking

Duplicate normalized article URLs within the run produce one row with sourceFeeds listing every matching source. URL fragments are removed; query strings remain significant. Different URLs describing the same story are **not** semantically merged. When duplicate URLs have different titles, the first supplied feed wins and a warning is included.

The first run writes SNAPSHOT. On later runs pass the previous run's key-value store ID in previousSnapshotStoreId, keep feed URLs and filters identical, and enable changesOnly. Unchanged headlines are suppressed. Modified titles, dates or categories produce field-level before/after evidence in changes. The workflow must update that store ID each time; no global shared history or automatic scheduled alert is included.

New means not observed in the supplied snapshot, not necessarily published today. Feeds often expose only recent entries, so this is not a historical news archive. Capped baselines can make previously unseen entries appear new in a later run. Missing entries are not labeled deleted. For consistent comparisons, do not roll the date filter forward between runs.

### Delivered fields and exports

| Field | Meaning |
|---|---|
| title, url | Feed headline and original article link |
| feedTitle, sourceFeeds | Publisher/feed context and deduplication provenance |
| publishedAt, sourcePublishedRaw | Parsed UTC date and source date; null if unavailable |
| categories | Source categories, not inferred labels |
| changeType, changedFields, changes | New/changed/unchanged and field-level evidence |
| firstObservedAt, observedAt | Your workflow's observation times |
| warnings | Missing dates, conflicting titles and truncation notes |

JSON and standard Apify dataset exports are available. OUTPUT-CSV is UTF-8 and spreadsheet-formula-safe; JSON retains original text. SUMMARY reports duplicate counts, skipped invalid entries, errors and coverage; DELIVERY records export completeness; DIAGNOSTICS contains unchecked feeds; SNAPSHOT supports your next comparison.

### Pricing and bounds

**$1 per 1,000 delivered feed items ($0.001 each)** plus the displayed Actor start charge, with platform usage included and no monthly rental. Duplicate URLs, filtered-out items and suppressed unchanged rows are not charged as feed items. A blocked, malformed or inaccessible feed produces an uncharged diagnostic. The start charge can apply even if no item matches.

Up to 20 feeds, 1,000 delivered items per run (50 default), 1.5 MB per feed response and an approximately 90-second request budget. XML depth and element counts are bounded; DTDs and custom entities are rejected. Set Apify's maximum charge before starting. If the result or time limit intervenes, SUMMARY marks partial coverage. Snapshots retain up to 10,000 recent records.

### Access and content boundaries

Uses public HTTP with a truthful Tender Delta user agent and respects robots.txt and rate limits. No login, anti-bot bypass, JavaScript rendering, feed discovery, pagination, RDF/RSS 1.0 or JSON Feed support. Robots failures are handled conservatively. Private-network targets, IPv6-only destinations and nonstandard ports are unsupported. Article pages are never fetched; no article body, email list, translation or AI summary is delivered. Only titles up to 1,000 characters and other feed metadata are retained.

Publishers' feed and content terms apply; a public feed is not a blanket license to republish articles. Source links and attribution are preserved so your team can review originals.

[RSS 2.0 specification](https://www.rssboard.org/rss-specification), [Atom specification](https://www.rfc-editor.org/rfc/rfc4287). Independent tool by **Tender Delta**, not affiliated with the feed publishers. Report reproducible issues in this Actor's Issues tab using input and a redacted run link.

# Actor input Schema

## `feeds` (type: `array`):

Up to 20 public RSS 2.0 or Atom 1.0 feeds. Direct feed URLs; no website feed discovery.

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

Case-insensitive OR filter. Empty includes all feed items.

## `publishedSince` (type: `string`):

UTC ISO date-time, such as 2026-09-01T00:00:00Z. Excludes items with missing dates. Keep fixed when comparing snapshots.

## `maxItems` (type: `integer`):

Limits work and delivered results; inspect SUMMARY for coverage.

## `changesOnly` (type: `boolean`):

Needs your previous snapshot to suppress unchanged observations. New means not seen in that snapshot.

## `previousSnapshotStoreId` (type: `string`):

Optional previous run store containing SNAPSHOT. Your workflow must pass the preceding run defaultKeyValueStoreId on each run. Keep target lists and filters identical.

## Actor input object example

```json
{
  "feeds": [
    "https://www.nasa.gov/feed/"
  ],
  "keywords": [],
  "maxItems": 50,
  "changesOnly": false
}
```

# Actor output Schema

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

No description

## `csv` (type: `string`):

No description

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

No description

## `files` (type: `string`):

No description

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

// Run the Actor and wait for it to finish
const run = await client.actor("longish_whistle/rss-news-dedup-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 = {
    "feeds": ["https://www.nasa.gov/feed/"],
    "keywords": [],
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("longish_whistle/rss-news-dedup-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 '{
  "feeds": [
    "https://www.nasa.gov/feed/"
  ],
  "keywords": [],
  "maxItems": 50
}' |
apify call longish_whistle/rss-news-dedup-change-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,longish_whistle/rss-news-dedup-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/j62kYtL1amra7OF6m/builds/06p9ebMQMFvfusWUk/openapi.json
