# News Monitor: Keyword News + RSS Feeds, Deduplicated (`kempt_horizon_yzk/news-monitor`) Actor

Monitor news by keyword (GDELT global news index) and your own publisher RSS/Atom feeds. Returns only new articles since the last run, removes duplicates across sources, tags companies and tickers from your watchlist. Respects robots.txt. $0.001/article.

- **URL**: https://apify.com/kempt_horizon_yzk/news-monitor.md
- **Developed by:** [Kempt Horizon Data](https://apify.com/kempt_horizon_yzk) (community)
- **Categories:** News, Automation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 1,000 new articles

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?

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

## News Monitor: Keyword News Alerts + RSS/Atom Feeds, Deduplicated, with Company Tags

Track the news for **any keyword, company or topic**, plus **your own publisher RSS/Atom feeds**, and get **only the new articles since your last run**. The same story syndicated across many sites is collapsed into one item (**canonical URL plus title-similarity matching**), with the other outlets listed under `alsoReportedBy`. Add a **watchlist** (company names, tickers, aliases) and each article is tagged with the companies and tickers it mentions. Schedule it every hour for a clean news feed in Slack, email, Sheets or your app.

### Where the news comes from

- **Keyword search:** the **GDELT Project** DOC 2.0 API, an open, free index of world news in 100+ languages, updated every 15 minutes. GDELT rate-limits busy cloud IP ranges, so on some runs it refuses requests; the run then continues with your feeds and notes it in `RUN_SUMMARY.errors`. For dependable coverage, add the publisher feeds you care about.
- **Keywords also filter your feeds:** when you give both, feed items must mention one of your keywords (whole-word match).
- **Your feeds:** any RSS 2.0 or Atom feed you add. The Actor checks each site's **robots.txt** first and skips disallowed feeds. You are responsible for using feeds within their publishers' terms.
- **Google News RSS is not used.** Its feed terms allow only personal, non-commercial feed readers, which rules out a paid tool.

### For AI agents (MCP / API) quick reference

- **Use when:** you need recent news articles for keywords or companies, deduplicated, with only new items since the last check, or company/ticker tags for a watchlist.
- **Don't use for:** full article text (only title, link, date, source and the feed summary are returned), paywalled content, or social media.
- **Minimal input:** `{"searchQueries": ["Nvidia"], "maxItems": 20}`.
- **Output:** one dataset item per new article: `title`, `url`, `canonicalUrl`, `source`, `publishedAt`, `summary`, `language`, `sourceCountry`, `imageUrl`, `companies`, `tickers`, `matchedQuery`, `foundVia` (gdelt or feed), `alsoReportedBy`.
- **Price:** **$0.001 per new article**, no start fee. Duplicates and already-seen articles are free. Pay per event only, limited permissions, so agentic payments (x402, Skyfire, Apify AGI token) work.
- **MCP:** add `https://mcp.apify.com?tools=kempt_horizon_yzk/news-monitor` to your MCP client.

### What can it do?

- ✅ **Keyword news search** across global news via GDELT, with quotes, OR and minus
- ✅ **Your RSS/Atom feeds** in the same output, with robots.txt checked first
- ✅ **Cross-source deduplication** by canonical URL (tracking parameters, AMP and www removed) and title similarity
- ✅ **Watchlist tagging** for companies, tickers and aliases, with an option to keep only matching articles
- ✅ **Monitor mode** on by default: remembers 30 days of URLs and titles in a key-value store and returns only new stories

### Who uses it?

PR and comms teams, investor relations, traders and analysts following tickers, competitive intelligence, newsletter editors, and AI agents that need fresh news.

### How much does it cost?

| Event | Price |
|---|---|
| New article | **$0.001** |

Hourly monitoring of 10 keywords that finds 300 new articles a day costs about $0.30 a day.

### Input example

```json
{
  "searchQueries": ["Nvidia", "\"data center\" AND power"],
  "feeds": ["https://techcrunch.com/feed/", "https://feeds.bbci.co.uk/news/business/rss.xml"],
  "watchlist": ["Nvidia|NVDA|GeForce", "Alphabet|GOOGL|Google", "Microsoft|MSFT|Azure"],
  "lookbackHours": 24,
  "maxItems": 200,
  "onlyNew": true,
  "stateKey": "ai-chips-news"
}
```

### Output example

```json
{
  "title": "Adobe Rebuilt Photoshop And Premiere For NVIDIA RTX Spark Platform",
  "url": "https://www.engadget.com/2287388/adobe-rebuilt-photoshop-and-premiere-for-nvidia-rtx-spark/",
  "canonicalUrl": "engadget.com/2287388/adobe-rebuilt-photoshop-and-premiere-for-nvidia-rtx-spark",
  "source": "engadget.com",
  "publishedAt": "2026-10-15T13:30:00Z",
  "summary": null,
  "language": "English",
  "sourceCountry": "Japan",
  "imageUrl": "https://www.engadget.com/img/gallery/adobe-rebuilt-photoshop-and-premiere-for-nvidias-rtx-spark-platform/l-intro-1792065422.jpg",
  "companies": [
    "Nvidia"
  ],
  "tickers": [
    "NVDA"
  ],
  "matchedQuery": "Nvidia",
  "foundVia": "gdelt",
  "feedUrl": null,
  "alsoReportedBy": [],
  "scrapedAt": "2026-10-15T14:09:14.740Z"
}
```

### FAQ

**Why is a keyword article's title missing my keyword?** GDELT matches the full article text, not just the title.

**Does it return full article text?** No. Use the URL to read the article on the publisher's site.

Built and maintained by **Kempt Horizon Data**. Found a bug or need a field? Open an issue on the Actor's Issues tab and we usually reply within a day. Not affiliated with GDELT, Google or any publisher.

# Actor input Schema

## `searchQueries` (type: `array`):

Keywords. Searched in the GDELT global news index, and also used to filter your feeds (feed items must mention a keyword). Supports quotes, OR and minus in GDELT.

## `useGdelt` (type: `boolean`):

Also search the GDELT global news index for the keywords. GDELT rate-limits busy cloud IPs; if it refuses, the run continues with your feeds and the run summary notes it.

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

Optional feed URLs, e.g. https://techcrunch.com/feed/. robots.txt is checked before each feed is read. Only add feeds whose terms allow your use.

## `watchlist` (type: `array`):

Optional. One entry per company: Name|TICKER|alias|alias, e.g. Alphabet|GOOGL|Google|YouTube. Matching articles get companies and tickers tags.

## `onlyWatchlistMatches` (type: `boolean`):

Skip (and don't charge for) articles that mention no watchlist company in the title or summary.

## `language` (type: `string`):

GDELT source language for keyword searches (e.g. english, german, spanish). Empty = all languages.

## `lookbackHours` (type: `integer`):

Ignore articles older than this.

## `titleSimilarity` (type: `number`):

Two articles count as duplicates if their canonical URL matches or their title word overlap is at least this (0.8 = 80%).

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

Maximum new articles to save (and pay for) per run.

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

Remembers article URLs and titles (30 days) in a key-value store and returns only new stories.

## `stateKey` (type: `string`):

Optional name for the monitor memory.

## Actor input object example

```json
{
  "searchQueries": [
    "Nvidia"
  ],
  "useGdelt": true,
  "watchlist": [
    "Nvidia|NVDA",
    "Apple|AAPL"
  ],
  "onlyWatchlistMatches": false,
  "language": "english",
  "lookbackHours": 24,
  "titleSimilarity": 0.8,
  "maxItems": 20,
  "onlyNew": true
}
```

# Actor output Schema

## `articles` (type: `string`):

No description

## `all` (type: `string`):

No description

## `summary` (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 = {
    "searchQueries": [
        "Nvidia"
    ],
    "watchlist": [
        "Nvidia|NVDA",
        "Apple|AAPL"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("kempt_horizon_yzk/news-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 = {
    "searchQueries": ["Nvidia"],
    "watchlist": [
        "Nvidia|NVDA",
        "Apple|AAPL",
    ],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("kempt_horizon_yzk/news-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 '{
  "searchQueries": [
    "Nvidia"
  ],
  "watchlist": [
    "Nvidia|NVDA",
    "Apple|AAPL"
  ],
  "maxItems": 20
}' |
apify call kempt_horizon_yzk/news-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kempt_horizon_yzk/news-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/8QTrbRAjUcAwmPRXW/builds/uW67LQFwem7M6R0rS/openapi.json
