# RSS Keyword Monitor — Only New Items & Webhooks (`uplifted_novice_vbl/rss-keyword-monitor-only-new`) Actor

RSS feed monitor for keyword, regex, and exclusion filters across RSS, Atom, and RDF. Supports RSS-to-webhook delivery and JSON output, returning only new matching items per Task.

- **URL**: https://apify.com/uplifted\_novice\_vbl/rss-keyword-monitor-only-new.md
- **Developed by:** [Telemark Digital](https://apify.com/uplifted_novice_vbl) (community)
- **Categories:** Automation, Developer tools, News
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 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.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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 Keyword Monitor is an RSS feed monitor for keyword and regex alerts.** It monitors RSS, Atom, and RDF feeds on an Apify Schedule and returns only matching items that are new within the Task's deduplication window, as structured JSON and optional webhooks.

### What RSS Keyword Monitor does

Give it a list of feed URLs and (optionally) keywords, regex patterns, and exclude terms. Run it on an [Apify Schedule](https://docs.apify.com/platform/schedules) — hourly, every 15 minutes, daily, whatever. On each run it:

- fetches every feed (sending `If-None-Match` / `If-Modified-Since`, so unchanged feeds return **304 and cost nothing**),
- parses RSS 2.0, Atom 1.0 and RSS 1.0 (RDF), handling legacy encodings and broken feeds without crashing,
- keeps a durable per-Task **seen-set**, so it suppresses repeat delivery within your configured dedup window,
- filters by keyword / regex, drops your exclude terms, and
- writes one clean JSON record per new item to the dataset — and **only charges for those new items**.

It turns a schedule (or an AI agent poll) into a cheap, recurring _"what's new in my feeds"_ event stream. You can download the results as JSON, CSV, Excel or HTML, pull them from the API, wire them into n8n / Make / Zapier, or call it as an MCP tool.

### When to use it — and when NOT to (please read this)

This Actor is honest about where it wins. Use it when you have **specific feeds + filtering + cross-run dedup + one batched machine-readable call**. Don't use it for these three cases — we'll tell you the better tool:

- **One-off bulk reads of a feed?** Use a plain feed reader (e.g. `automation-lab/rss-feed-reader`). It's cheaper _per item_ for a single full dump. We're built for the recurring _delta_, not the archive pull — and on a one-shot read we're honestly ~2× more expensive per item.
- **Watching just 1–3 feeds, unfiltered?** A free **n8n RSS Feed Trigger** (self-hosted) or **Make "Watch RSS feed items"** will do it. We start paying off when you have _many_ feeds, keyword/regex filtering, and want cross-run dedup state without wiring up custom code.
- **A human reading keyword alerts in an inbox?** **Inoreader Pro** (~€6.67/mo, 2,500 feeds, 30 alert rules) or **Feedly** beat us for eyeballs. We are not an inbox — no reading UI, no ≤1h "refresh." We emit structured per-item JSON deltas for machines.

Still here? Then you're the buyer: an automation operator or agent feeding a **pipeline**, not an inbox.

### How much does it cost?

Two events: **$0.005 per run** (`actor-start`) and **$0.002 per new matching item** (`new-item`, i.e. $2.00 per 1,000 _new_ items). You are charged **only for new items after filtering** — duplicates, excluded items, unchanged (304) feeds and failed feeds are never billed. A quiet hourly watch is dominated by the tiny per-run fee, and most of those runs find nothing new.

| Your workload                               | This Actor                               | A stateless reader charging per item every poll    | You save                    |
| ------------------------------------------- | ---------------------------------------- | -------------------------------------------------- | --------------------------- |
| 20 feeds, **hourly**, ~2 new matching/run   | 720 × ($0.005 + 2×$0.002) = **$6.48/mo** | 720 × ($0.035 + ~200×$0.001) = **$169/mo**         | **~26×**                    |
| Same, their most defensive 1-item config    | —                                        | 720 × $0.055 = **$39.60/mo** (misses bursts)       | **~6×**                     |
| 20 feeds, **daily digest**, ~40 new/day     | 30 × ($0.005 + 40×$0.002) = **$2.55/mo** | 30 × $0.235 = **$7.05/mo**                         | ~2.8×                       |
| **One-shot** bulk read, 10 feeds × 50 items | $0.005 + 500×$0.002 = **$1.01**          | $0.035 + 500×$0.001 = **$0.54**                    | _they win ~1.9× — use them_ |
| vs **Make** native, 50 feeds @ 15-min       | 2,880 × $0.005 + items ≈ **$15–20/mo**   | ~144k ops/mo ≈ **$30+/mo** tier, no keyword filter | ~2× + filtering             |

The wedge is the per-run fee and the fact that scheduled watches are _mostly duplicates_ — which you shouldn't pay to receive again. On a hot, always-changing firehose (every item is new), the per-item price dominates and a plain reader is cheaper; if that's you, use one.

> Only users on a **paid Apify plan** are billed; the free tier's monthly credit lets you trial it. Prices can change with 14 days' notice (Apify policy).

### 2-minute quickstart

1. Click **Try for free**.
2. In **Feed URLs**, paste one or more feeds (defaults are prefilled so you can just hit Start).
3. Optionally add **Keywords** (e.g. `acquisition`, `funding round`) — leave empty to get every new item.
4. Click **Start**. The first run seeds the seen-set and returns matching items (up to _Max items per run_).
5. Run it again — you'll get **0 new items** (everything's already been delivered). That's the point.

### Run it on a schedule (the whole point)

Cross-run dedup only makes sense on a **Task + Schedule**, because state is keyed by Task.

1. Configure the input, then **Create task ▸**.
2. Open the Task ▸ **Schedule** ▸ e.g. _every hour_.
3. Add a **Webhook URL** (below) to get pushed only when there's something new.

Example Task input:

```json
{
    "feeds": [
        "https://hnrss.org/frontpage",
        "https://www.theverge.com/rss/index.xml",
        "https://feeds.bbci.co.uk/news/rss.xml"
    ],
    "keywords": ["acquisition", "funding round", "layoffs"],
    "excludeTerms": ["rumor"],
    "matchFields": ["title", "description"],
    "onlyNew": true,
    "webhookUrl": "https://your-endpoint.example.com/rss-hook"
}
````

### Recipes

#### n8n

Replace *N* "RSS Feed Trigger" nodes + *N* "Filter" nodes with **one** node. Add an **HTTP Request** node (or the Apify node) that runs this Actor, or add a **Webhook** node and paste its URL into `webhookUrl` — you'll receive a POST only when there are new items. Self-hosted n8n users watching 1–3 feeds don't need us; 50-feed graphs do.

#### Make (Integromat)

Every Make scenario poll consumes operations even when nothing is new — a 50-feed 15-minute watch burns ~144k ops/mo before any processing, and the native RSS module has no keyword filter. Instead: one Apify run polls all feeds and returns only filtered deltas to a single **Custom webhook** module. Point `webhookUrl` at that module's URL.

#### Slack (or Discord / Teams)

Create an **Incoming Webhook** in Slack and put its URL in `webhookUrl`. Slack endpoints receive a concise text message with up to 10 item links. Other endpoints receive the raw JSON payload below.

#### Raw webhook payload

`webhookUrl` receives a POST (`Content-Type: application/json`) **only when there are new items**:

```json
{
    "summary": {
        "newItemsDelivered": 2,
        "feedsOk": 8,
        "feedsNotModified": 20,
        "feedsError": 0,
        "onlyNew": true,
        "chargeLimitReached": false,
        "webhookDelivered": true,
        "charge": { "actorStart": 1, "newItemEvents": 2 }
    },
    "items": [
        {
            "feedUrl": "…",
            "title": "…",
            "link": "…",
            "matchedTerms": ["acquisition"],
            "firstSeenAt": "…",
            "isNew": true
        }
    ],
    "itemsTruncated": false
}
```

`items` carries up to the 50 newest records; the full set is always in the dataset. A webhook failure is logged but never fails the run.

### Use it from an AI agent (MCP)

Eligible paid Apify Actors can be exposed through **[mcp.apify.com](https://mcp.apify.com/)** when you add them to your MCP server configuration. The *only-new* semantics fit agent polling — *"what's new in these feeds since I last asked?"* Call this Actor with `feeds` + `keywords`; on a Task it remembers what it already returned within the dedup window.

### Input

| Field            | Type     | Default                   | Notes                                                                                               |
| ---------------- | -------- | ------------------------- | --------------------------------------------------------------------------------------------------- |
| `feeds`          | string\[] | Apify blog + BBC samples  | RSS/Atom/RDF URLs, 1–500. Replace the samples with the feeds you want to monitor.                   |
| `keywords`       | string\[] | `[]`                      | Case-insensitive substrings, OR-matched. Empty = deliver every new item.                            |
| `regexPatterns`  | string\[] | `[]`                      | OR-matched with keywords (case-insensitive). Invalid pattern fails the run with a clear error.      |
| `excludeTerms`   | string\[] | `[]`                      | Drop matched items containing any of these. Applied **before** charging.                            |
| `matchFields`    | string\[] | `["title","description"]` | Any of `title`, `description`, `content`, `categories`.                                             |
| `onlyNew`        | boolean  | `true`                    | Off = plain filtered read of the current feeds (still charged per item).                            |
| `maxItemsPerRun` | integer  | `200`                     | Hard billing ceiling. In only-new mode, validators are held so overflow is retried on the next run. |
| `dedupWindow`    | integer  | `45`                      | Days an item stays in the seen-set (7–365).                                                         |
| `includeContent` | boolean  | `true`                    | Include `content:encoded` HTML per item when present. No article-page fetching.                     |
| `webhookUrl`     | string   | —                         | POSTed only when there are new items.                                                               |
| `resetState`     | boolean  | `false`                   | Wipe this Task's seen-set + HTTP validators. Use once, then turn off.                               |

### Output

One dataset record per **new** matching item:

```json
{
    "feedUrl": "https://hnrss.org/frontpage",
    "feedTitle": "Hacker News: Front Page",
    "feedType": "rss",
    "itemKey": "guid:https://news.ycombinator.com/item?id=44861023",
    "guid": "https://news.ycombinator.com/item?id=44861023",
    "title": "EU AI Act enforcement begins for foundation models",
    "link": "https://example.com/eu-ai-act",
    "author": "tosh",
    "publishedAt": "2026-07-11T08:14:02.000Z",
    "firstSeenAt": "2026-07-11T08:30:11.412Z",
    "categories": ["ai", "regulation"],
    "description": "Enforcement of the EU AI Act's obligations…",
    "content": "<p>Full content:encoded HTML when the feed provides it…</p>",
    "matchedTerms": ["eu ai act"],
    "isNew": true
}
```

A per-run **summary** (per-feed statuses, counts, charge totals, and spending-limit status) is written to the run's key-value store under `OUTPUT` — the dataset stays clean for pipelines. `firstSeenAt` is our server clock at first delivery. `publishedAt` is the feed's untrusted claim: it is never used as a time cursor, but it is part of the hash fallback when an item has neither GUID nor link.

### How the "only new" state works

- **Keyed by Task.** State lives under your Task ID, so **editing keywords or feeds never resets history** — no fragile manual snapshot key to fat-finger. Ad-hoc (non-Task) runs share a persistent per-user scope; create a Task for isolated recurring monitoring.
- **Sharded per feed** in a named key-value store, pruned on writes, capped at 20,000 identity keys/feed (oldest evicted). GUID items can use two keys. Eviction degrades to occasional re-delivery, not failure.
- **`dedupWindow`** controls how long an item is remembered. Feeds that legitimately re-surface an item older than the window will re-deliver it.
- **Redirects:** we follow up to 5; on a permanent (301) redirect we log the new URL and recommend you update it — state stays on the URL you configured, so renaming never orphans history.
- **`resetState: true`** fully wipes this Task's seen-set and stored validators for a clean start.

### Feed handling & reliability

- **Formats:** RSS 2.0, Atom 1.0, RSS 1.0 (RDF). (JSON Feed is not yet supported — it returns a clear per-feed error, not a crash.)
- **Encodings:** respects the Content-Type / XML-declaration charset with an `iconv` fallback for legacy JP/CN encodings; strips BOMs; tolerates leading whitespace; detects HTML error pages instead of choking on them.
- **Per-feed isolation:** each network attempt has a hard timeout and every response has a 10 MB cap; one dead, hostile or malformed feed becomes a single `error` row in the summary — **the run still succeeds** and you're not billed for it.
- **Politeness:** a descriptive User-Agent, `gzip` accepted, conditional GET on delta polls, bounded retries, and sequential requests for feeds configured on the same host. Redirects are bounded and revalidated. WAF-fronted feeds may still block cloud egress.

Run a recurring Task no more frequently than its previous run can finish. Concurrent runs of the same Task are not transactional and can race on shared state.

### How it compares

| Tool                           | Multi-feed  | Keyword/regex filter         | Cross-run dedup (only-new)     | Charges per *new* item | Webhook | For                             |
| ------------------------------ | ----------- | ---------------------------- | ------------------------------ | ---------------------- | ------- | ------------------------------- |
| **This Actor**                 | ✅ 1–500    | ✅ keyword + regex + exclude | ✅ Task-keyed, durable         | ✅                     | ✅      | pipelines / agents              |
| automation-lab/rss-feed-reader | ✅          | ➖ downstream                | ❌ (dedup downstream)          | ❌ per item every poll | ➖      | bulk reads                      |
| santamaria rss reader          | ✅          | ❌                           | ❌                             | per feed-fetch         | ❌      | bulk fetches                    |
| taroyamada feed aggregator     | ✅          | ✅ keywords                  | ✅ (manual `snapshotKey`)      | ✅                     | ✅      | credit where due — closest peer |
| n8n RSS Trigger (free)         | ➖ 1/node   | ✅ (Filter node)             | ❌ (needs custom `staticData`) | n/a (compute)          | ✅      | 1–few feeds, self-host          |
| Make "Watch RSS"               | ➖ 1/module | ❌                           | ✅ but burns ops each poll     | n/a (ops)              | ✅      | Make-native flows               |
| Inoreader / Feedly             | ✅          | ✅                           | ✅ (for reading)               | n/a (subscription)     | ➖      | humans reading alerts           |

No trash talk — several of these are great at what they do. We own exactly one lane: **scheduled, filtered, deduped, machine-readable feed deltas.**

### FAQ

**What does the first run return?** Everything currently matching (up to `maxItemsPerRun`), and it seeds the seen-set. Subsequent runs return only what's new since. To seed silently, set a low `maxItemsPerRun` on the first run.

**A feed has no GUIDs — will I get duplicates?** No. When `guid` is absent we key on `link`, and if that's missing too, on a stable hash of `feedUrl + title + pubDate`. We also guard against WordPress-style GUID rotation (same link+title, new guid → treated as already seen).

**A feed keeps re-surfacing old items.** They're suppressed while within `dedupWindow`. If they resurface after it, they re-deliver — raise the window if that's unwanted.

**Does editing keywords or feeds reset my history?** No — state is keyed by Task, not by your config.

**Why did a run "succeed" with a dead feed?** Per-feed isolation: the dead feed is an `error` row in the run summary (and unbilled); the rest of the run proceeds. Check the `OUTPUT` record for per-feed detail.

**Can it fetch the full article text?** No — it returns what the feed provides (`content:encoded` when present). Article-page extraction is a different, costlier job.

**JSON Feed?** Not yet — it returns a clear per-feed error rather than failing the run.

### Support

Found a bad feed or an edge case? Open an issue on the Actor's **Issues** tab with the feed URL — feed pathology is exactly what this Actor is built to handle well, and reports make it better.

# Actor input Schema

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

RSS 2.0 / Atom 1.0 / RSS 1.0 (RDF) feed URLs to monitor. 1–500 feeds. Each is fetched once per run regardless of how many keywords you set.

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

Case-insensitive substrings, OR-matched (e.g. "acquisition", "funding round"). Leave EMPTY to deliver every new item (no keyword filter).

## `regexPatterns` (type: `array`):

Regular expressions, OR-matched with keywords (case-insensitive). An invalid pattern fails the run fast with a clear error.

## `excludeTerms` (type: `array`):

Drop any item whose matched fields contain one of these (case-insensitive). Applied AFTER matching, BEFORE charging — excluded items are never billed.

## `matchFields` (type: `array`):

Which item fields keywords/regex are tested against. Allowed values: title, description, content, categories. Default: title + description.

## `onlyNew` (type: `boolean`):

When on (default), return and charge for items never delivered to this Task before. Turn off for a plain filtered read of the current feeds (still charged per item).

## `maxItemsPerRun` (type: `integer`):

Hard cap on items delivered/charged in a single run. In only-new mode, HTTP validators are withheld so overflow can be retried from the source feed next run; items are not durably queued and can disappear if the source removes them first.

## `dedupWindow` (type: `integer`):

How long an item stays in the seen-set. Feeds that re-surface an item older than this will re-deliver it. 7–365 days.

## `includeContent` (type: `boolean`):

Include the feed's full content:encoded HTML in each item when present. (No article-page fetching.) Turn off for smaller records.

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

Optional. POSTed a JSON payload (run summary + up to 50 newest items) only when there are new items. Works with n8n, Make, Slack, or any endpoint.

## `resetState` (type: `boolean`):

Wipe this Task's seen-set and stored HTTP validators and start fresh. Use once, then turn back off.

## Actor input object example

```json
{
  "feeds": [
    "https://blog.apify.com/rss/",
    "https://feeds.bbci.co.uk/news/rss.xml"
  ],
  "keywords": [],
  "regexPatterns": [],
  "excludeTerms": [],
  "matchFields": [
    "title",
    "description"
  ],
  "onlyNew": true,
  "maxItemsPerRun": 5,
  "dedupWindow": 45,
  "includeContent": true,
  "resetState": false
}
```

# Actor output Schema

## `items` (type: `string`):

Default dataset containing the matched RSS, Atom, or RDF item records emitted by this run.

## `runSummary` (type: `string`):

Run-level feed statuses, delivery counts, cap status, and charging summary.

# 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://blog.apify.com/rss/",
        "https://feeds.bbci.co.uk/news/rss.xml"
    ],
    "keywords": [],
    "onlyNew": false,
    "maxItemsPerRun": 5,
    "includeContent": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("uplifted_novice_vbl/rss-keyword-monitor-only-new").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://blog.apify.com/rss/",
        "https://feeds.bbci.co.uk/news/rss.xml",
    ],
    "keywords": [],
    "onlyNew": False,
    "maxItemsPerRun": 5,
    "includeContent": False,
}

# Run the Actor and wait for it to finish
run = client.actor("uplifted_novice_vbl/rss-keyword-monitor-only-new").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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://blog.apify.com/rss/",
    "https://feeds.bbci.co.uk/news/rss.xml"
  ],
  "keywords": [],
  "onlyNew": false,
  "maxItemsPerRun": 5,
  "includeContent": false
}' |
apify call uplifted_novice_vbl/rss-keyword-monitor-only-new --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=uplifted_novice_vbl/rss-keyword-monitor-only-new",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "RSS Keyword Monitor — Only New Items & Webhooks",
        "description": "RSS feed monitor for keyword, regex, and exclusion filters across RSS, Atom, and RDF. Supports RSS-to-webhook delivery and JSON output, returning only new matching items per Task.",
        "version": "0.1",
        "x-build-id": "ApH7X22XrCGbdPLkA"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/uplifted_novice_vbl~rss-keyword-monitor-only-new/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-uplifted_novice_vbl-rss-keyword-monitor-only-new",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/uplifted_novice_vbl~rss-keyword-monitor-only-new/runs": {
            "post": {
                "operationId": "runs-sync-uplifted_novice_vbl-rss-keyword-monitor-only-new",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/uplifted_novice_vbl~rss-keyword-monitor-only-new/run-sync": {
            "post": {
                "operationId": "run-sync-uplifted_novice_vbl-rss-keyword-monitor-only-new",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "feeds": {
                        "title": "Feed URLs",
                        "minItems": 1,
                        "maxItems": 500,
                        "uniqueItems": true,
                        "type": "array",
                        "description": "RSS 2.0 / Atom 1.0 / RSS 1.0 (RDF) feed URLs to monitor. 1–500 feeds. Each is fetched once per run regardless of how many keywords you set.",
                        "items": {
                            "type": "string",
                            "maxLength": 2048
                        },
                        "default": [
                            "https://blog.apify.com/rss/",
                            "https://feeds.bbci.co.uk/news/rss.xml"
                        ]
                    },
                    "keywords": {
                        "title": "Keywords / phrases",
                        "maxItems": 100,
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Case-insensitive substrings, OR-matched (e.g. \"acquisition\", \"funding round\"). Leave EMPTY to deliver every new item (no keyword filter).",
                        "items": {
                            "type": "string",
                            "maxLength": 200
                        },
                        "default": []
                    },
                    "regexPatterns": {
                        "title": "Regex patterns",
                        "maxItems": 50,
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Regular expressions, OR-matched with keywords (case-insensitive). An invalid pattern fails the run fast with a clear error.",
                        "items": {
                            "type": "string",
                            "maxLength": 500
                        },
                        "default": []
                    },
                    "excludeTerms": {
                        "title": "Exclude terms",
                        "maxItems": 100,
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Drop any item whose matched fields contain one of these (case-insensitive). Applied AFTER matching, BEFORE charging — excluded items are never billed.",
                        "items": {
                            "type": "string",
                            "maxLength": 200
                        },
                        "default": []
                    },
                    "matchFields": {
                        "title": "Fields to match on",
                        "maxItems": 4,
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Which item fields keywords/regex are tested against. Allowed values: title, description, content, categories. Default: title + description.",
                        "items": {
                            "type": "string",
                            "maxLength": 11
                        },
                        "default": [
                            "title",
                            "description"
                        ]
                    },
                    "onlyNew": {
                        "title": "Only new items",
                        "type": "boolean",
                        "description": "When on (default), return and charge for items never delivered to this Task before. Turn off for a plain filtered read of the current feeds (still charged per item).",
                        "default": true
                    },
                    "maxItemsPerRun": {
                        "title": "Max items per run (billing ceiling)",
                        "minimum": 1,
                        "maximum": 2000,
                        "type": "integer",
                        "description": "Hard cap on items delivered/charged in a single run. In only-new mode, HTTP validators are withheld so overflow can be retried from the source feed next run; items are not durably queued and can disappear if the source removes them first.",
                        "default": 200
                    },
                    "dedupWindow": {
                        "title": "Dedup window (days)",
                        "minimum": 7,
                        "maximum": 365,
                        "type": "integer",
                        "description": "How long an item stays in the seen-set. Feeds that re-surface an item older than this will re-deliver it. 7–365 days.",
                        "default": 45
                    },
                    "includeContent": {
                        "title": "Include full content",
                        "type": "boolean",
                        "description": "Include the feed's full content:encoded HTML in each item when present. (No article-page fetching.) Turn off for smaller records.",
                        "default": true
                    },
                    "webhookUrl": {
                        "title": "Webhook URL",
                        "type": "string",
                        "description": "Optional. POSTed a JSON payload (run summary + up to 50 newest items) only when there are new items. Works with n8n, Make, Slack, or any endpoint."
                    },
                    "resetState": {
                        "title": "Reset state",
                        "type": "boolean",
                        "description": "Wipe this Task's seen-set and stored HTTP validators and start fresh. Use once, then turn back off.",
                        "default": false
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
