# Brand News Monitor & GDELT Mention Alerts (`johnatan029/brand-news-monitor`) Actor

Monitor brands in global news with persistent deduplication. Get only genuinely new GDELT mentions, filter by language and source country, catch syndicated duplicates by normalized title, and receive free per-brand velocity and publisher-domain summaries. First run creates a free baseline.

- **URL**: https://apify.com/johnatan029/brand-news-monitor.md
- **Developed by:** [Johnn Mottin](https://apify.com/johnatan029) (community)
- **Categories:** News, Automation, Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 new mentions

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

### Monitor global brand news and receive only genuinely new mentions

Track brands, companies, products, executives, competitors, or topics across global online news through the **GDELT DOC 2.0 API**.

This Actor is stateful. Each brand × language × source-country dimension remembers what it has already shown you, so scheduled runs do not keep billing the same article again.

The first successful observation creates a **free baseline**. Later runs emit `NEW_MENTION` only for article URLs that have not already been seen in that monitoring dimension.

An optional second deduplication layer catches syndicated republications that reuse the same normalized headline under a different URL.

No browser automation. No news-site login. No LLM or fuzzy matching in runtime.

#### Key features

- **Stateful brand-news monitoring**
- **Genuinely new article mentions only**
- **Persistent deduplication by publisher URL**
- **Optional normalized-title deduplication**
- **Free first-run baseline**
- **Brand, company, product, executive, competitor, or topic queries**
- **Language filtering**
- **Source-country filtering**
- **Independent brand × language × country state**
- **Publisher URL**
- **Article title**
- **Publisher domain**
- **Article/source language**
- **Source country**
- **GDELT seen date**
- **Per-dimension article velocity**
- **Top publisher domains in the current window**
- **Top domains among delivered new mentions**
- **Free BRAND\_SUMMARY on every successful dimension**
- **Free RUN\_SUMMARY**
- **Up to 40 monitored dimensions per run**
- **Controlled GDELT request pacing**
- **Pay Per Event**

> **Unofficial community Actor. Not affiliated with, sponsored by, or endorsed by the GDELT Project or by any publisher returned in the results.** Data comes from the GDELT Project. GDELT's published Terms of Use permit commercial use and redistribution of its datasets, with GDELT attribution required when the data is redistributed.

***

### What this Actor is for

A news scraper answers:

> Which articles match this query right now?

A monitoring product should answer:

> Which matching articles are new since I last checked?

This Actor maintains persistent state for every monitored dimension and is designed for:

- brand monitoring;
- PR and communications;
- media intelligence;
- competitor monitoring;
- executive monitoring;
- product-launch coverage;
- reputation research;
- crisis monitoring;
- market research;
- recurring media reports;
- Slack/news alert workflows;
- data warehouses and dashboards.

***

### Important: first run is a free baseline

For each new:

```text
brand × language × country
```

dimension, the first successful run learns the current article IDs.

It does not present those existing rows as new mentions.

Example:

```text
First run
75 articles in the GDELT window
75 URLs learned
0 NEW_MENTION records
```

If later 6 unseen article URLs appear:

```text
Next run
6 genuinely unseen mentions
6 NEW_MENTION records
```

This prevents normal lookback overlap from becoming repeated billing.

***

### Persistent novelty state

The primary deduplication identity is derived from the publisher URL returned by GDELT.

The Actor computes a deterministic 16-character ID from:

```text
SHA-256(article URL)
```

and persists it for the monitoring dimension.

A `NEW_MENTION` therefore means:

```text
this article URL was not already present
in this brand × language × country state
```

***

### Optional title deduplication

By default:

```json
{
  "dedupeTitles": true
}
```

The Actor also normalizes titles by:

- lowercasing;
- removing accents;
- collapsing punctuation/whitespace.

Example:

```text
Company X Launches New Product!
```

and:

```text
company x launches new product
```

normalize to the same deterministic title key.

If that title was already seen, a different URL can be suppressed as a likely syndicated republication.

#### Important

This is exact normalized-title matching.

It is **not**:

- fuzzy matching;
- semantic similarity;
- clustering;
- AI classification.

Two genuinely different stories with the same normalized headline can therefore be treated as duplicates when title deduplication is enabled.

Disable it when URL-level novelty is more important than syndication suppression.

***

### Who it's for

#### PR and communications teams

Monitor:

- company name;
- product names;
- executives;
- campaigns;
- major announcements.

Send new mentions to a media-review workflow instead of manually re-running searches.

#### Brand and reputation teams

Build recurring visibility into:

- mention velocity;
- publisher domains;
- languages;
- source countries;
- genuinely new article coverage.

#### Agencies

Use separate labels and queries for multiple clients, brands, campaigns, or executives.

#### Competitive intelligence teams

Track public coverage of competitors or sectors.

#### Automation and data teams

Connect results to:

- Slack;
- Microsoft Teams;
- email workflows;
- n8n;
- Make;
- webhooks;
- databases;
- BI tools;
- dashboards;
- AI analysis downstream.

The Actor itself does not read article bodies or generate AI summaries.

***

### Data source — GDELT DOC 2.0

The Actor uses:

```text
https://api.gdeltproject.org/api/v2/doc/doc
```

with:

```text
mode=artlist
format=json
sort=datedesc
```

The query can also include GDELT filters for:

```text
sourcelang
sourcecountry
```

The implementation deliberately spaces GDELT API requests by at least 5 seconds and retries controlled rate-limit or transient failures with bounded backoff.

***

### GDELT usage terms

GDELT describes itself as an open platform for research and analysis.

Its published Terms of Use state that GDELT datasets may be used for academic, commercial, and governmental purposes without a dataset fee.

GDELT also permits redistribution/rehosting of its datasets, with attribution to the GDELT Project and a link to the project website required when redistributing the data.

Source:

```text
https://www.gdeltproject.org/about.html
```

This Actor returns article metadata and publisher URLs from GDELT.

Users remain responsible for how they use publisher content and for any rights or terms that apply to the destination articles themselves.

***

### Input

#### Recommended example

```json
{
  "brands": [
    {
      "query": "\"Anthropic\"",
      "label": "Anthropic"
    },
    {
      "query": "\"OpenAI\"",
      "label": "OpenAI"
    }
  ],
  "languages": [
    "english"
  ],
  "countries": [],
  "timespanHours": 72,
  "maxRecordsPerQuery": 75,
  "dedupeTitles": true,
  "maxResults": 500,
  "maxRuntimeMs": 300000
}
```

#### Input fields

| Field | Default | Description |
|---|---:|---|
| `brands` | required | GDELT brand/topic queries. Bare strings or `{ query, label }` objects. |
| `languages` | `["english"]` | GDELT `sourcelang` values. Empty list = all languages as one dimension. |
| `countries` | `[]` | GDELT `sourcecountry` codes. Empty list = all source countries. |
| `timespanHours` | `72` | GDELT lookback window. Range: 1–168 hours. |
| `maxRecordsPerQuery` | `75` | Maximum article rows read per dimension. Range: 10–250. |
| `dedupeTitles` | `true` | Optional second deduplication layer by normalized headline. |
| `maxResults` | `500` | Maximum billable `NEW_MENTION` records. Range: 1–5,000. |
| `maxRuntimeMs` | `300000` | Hard runtime cap in milliseconds. |
| `debug` | `false` | Additional diagnostic logging. |

***

### Brand query format

You can use a bare string:

```json
{
  "brands": [
    "\"Anthropic\""
  ]
}
```

or provide a label:

```json
{
  "brands": [
    {
      "query": "\"Anthropic\"",
      "label": "Anthropic"
    }
  ]
}
```

The `query` is passed into the GDELT DOC query expression.

For exact brand names, quoting the phrase is often useful:

```text
"Anthropic"
"OpenAI"
"Acme Corporation"
```

The Actor does not rewrite the user's GDELT query into an AI-generated search expression.

***

### Brand labels and persistent state

Persistent state is keyed partly by a normalized brand label.

Therefore two different queries must not use labels that normalize to the same slug.

Example of an invalid collision:

```json
{
  "brands": [
    {
      "query": "\"Acme\"",
      "label": "Acme"
    },
    {
      "query": "\"Acme AI\"",
      "label": "ACME"
    }
  ]
}
```

Both labels normalize to:

```text
acme
```

The revised validator rejects that collision instead of silently sharing or dropping state.

Exact duplicate entries with the same normalized label and same query are deduplicated.

***

### Language dimensions

Example:

```json
{
  "languages": [
    "english",
    "portuguese"
  ]
}
```

creates independent dimensions such as:

```text
anthropic / english / all-countries
anthropic / portuguese / all-countries
```

Leave the array empty to monitor all languages as one dimension:

```json
{
  "languages": []
}
```

Use the empty-list form for "all languages"; the literal string `all` is rejected.

***

### Source-country dimensions

Example:

```json
{
  "countries": [
    "US",
    "BR"
  ]
}
```

creates separate country dimensions.

Leave the list empty for all source countries:

```json
{
  "countries": []
}
```

Use the empty-list form for all countries; the literal `ALL` is rejected.

***

### Dimension cap

The number of monitored dimensions is:

```text
brands × language dimensions × country dimensions
```

Maximum:

```text
40
```

Examples:

```text
10 brands × 1 language × all countries = 10 dimensions
5 brands × 2 languages × 3 countries = 30 dimensions
10 brands × 2 languages × 3 countries = 60 dimensions → invalid
```

The cap exists because GDELT requests are intentionally paced.

Split larger portfolios across separate Tasks.

***

### Collection window and schedule overlap

The default:

```json
{
  "timespanHours": 72
}
```

is intentionally larger than a daily schedule interval.

That creates overlap.

Overlap is useful because it reduces the chance that an article falls between two runs.

Persistent deduplication means the overlap should not create a second `NEW_MENTION` charge for an already-seen URL.

***

### Article read cap

GDELT returns at most the configured:

```text
maxRecordsPerQuery
```

for each dimension.

Current Actor range:

```text
10–250
```

If more matching news articles exist in the lookback window than the requested result cap, older matching articles can be outside the returned slice.

For very high-volume brands:

- reduce `timespanHours`;
- schedule more frequently;
- raise `maxRecordsPerQuery` up to 250;
- narrow the query/language/country.

***

### Output

The dataset can contain:

```text
NEW_MENTION
BRAND_SUMMARY
RUN_SUMMARY
```

***

### `NEW_MENTION`

This is the billable record.

It is emitted only when:

- the monitored dimension is past baseline;
- the article has a usable publisher URL;
- the URL identity was not already seen;
- optional title deduplication does not suppress it;
- result/runtime/billing caps allow delivery.

#### Example

```json
{
  "recordType": "NEW_MENTION",
  "entityId": "listening:news:anthropic/72f9063c2bedf361",
  "source": "news",
  "brand": "anthropic",
  "brandLabel": "Anthropic",
  "query": "\"Anthropic\"",
  "url": "https://example.com/news/anthropic-announcement",
  "title": "Anthropic Announces New Product",
  "domain": "example.com",
  "language": "English",
  "sourcecountry": "United States",
  "seendate": "2026-08-26T13:15:00Z",
  "mentionId": "72f9063c2bedf361",
  "observedAt": "2026-08-26T17:00:00.000Z"
}
```

***

### `NEW_MENTION` fields

| Field | Description |
|---|---|
| `recordType` | `NEW_MENTION`. |
| `entityId` | Stable JM Forge mention identity. |
| `source` | `news`. |
| `brand` | Normalized brand slug. |
| `brandLabel` | User-facing brand label. |
| `query` | GDELT query used for this brand. |
| `url` | Publisher article URL returned by GDELT. |
| `title` | Article title. |
| `domain` | Publisher domain. |
| `language` | Language returned by GDELT. |
| `sourcecountry` | Source country returned by GDELT. |
| `seendate` | GDELT seen date normalized to ISO when possible. |
| `mentionId` | Deterministic URL-derived identity. |
| `observedAt` | Actor observation timestamp. |

***

### What this Actor does not extract

The current contract does not return:

```text
full article body
author/byline
publisher audience/reach
social share count
sentiment
article summary
AI topic classification
```

It returns GDELT article metadata and a publisher URL.

Use a separate content-extraction or AI-analysis step downstream when needed.

***

### `BRAND_SUMMARY`

Every successfully processed dimension receives a free summary.

It can include:

```text
brand
brandLabel
language
country
baseline
articlesInWindow
newMentions
mentionsDelivered
seenBefore
skippedNoUrl
velocityPer24h
topDomains
topNewMentionDomains
observedAt
```

***

### Article velocity

The free:

```text
velocityPer24h
```

normalizes the number of articles returned by the configured GDELT window to a 24-hour rate.

Example:

```text
72-hour window
90 articles returned
velocityPer24h = 30
```

#### Honest limitation

This is based on the article rows actually returned by GDELT inside `maxRecordsPerQuery`.

If the query is truncated by the per-dimension result cap, the calculated velocity is a lower-bound representation of the returned slice rather than a complete count of every matching article.

***

### Publisher-domain intelligence

`BRAND_SUMMARY.topDomains` now represents the top publisher domains among all article rows returned in the current GDELT window.

`BRAND_SUMMARY.topNewMentionDomains` represents the top domains among `NEW_MENTION` records actually delivered in the current run.

This distinction makes a quiet run useful:

```text
no new billable mention
but current source mix remains visible
```

***

### `RUN_SUMMARY`

The free final summary can include:

```text
billableRecords
freeRecords
baselineDimensions
httpRequests
http429
httpRetries
topDomainsOverall
capReason
qualityAlert
sourceUnavailable
warnings
units
cost
pricingLabel
```

`topDomainsOverall` refers to publisher domains among the billable new mentions delivered across the run.

***

### Persistent state limits

Each monitored dimension keeps bounded state for up to:

```text
5,000 URL identities
5,000 normalized title keys
```

The newest retained entries win as the state grows.

For ordinary brand monitoring this provides a long dedup horizon.

Very high-volume monitoring dimensions can eventually age old identities out of bounded state.

***

### Request pacing and retries

GDELT APIs are rate limited.

The Actor enforces a minimum:

```text
5 seconds
```

between GDELT requests.

Transient failures can use controlled retry delays with jitter.

The Actor tracks:

```text
httpRequests
http429
httpRetries
```

and surfaces source/quality problems instead of fabricating articles.

***

### Scheduling

This Actor is designed for scheduled monitoring.

A practical starting configuration:

```text
daily schedule
72-hour lookback
```

The overlapping window reduces gaps while persistent state suppresses repeated URLs.

For fast-moving campaigns or crises, use a shorter schedule if the query volume can exceed your `maxRecordsPerQuery` window between runs.

***

### Recommended scheduled workflow

1. Add the brand queries.
2. Run once to create free baseline state.
3. Save the input as an Apify **Task**.
4. Open **Schedules**.
5. Choose the cadence.
6. Send future `NEW_MENTION` records downstream.

Possible destinations:

- Slack;
- Microsoft Teams;
- email workflows;
- n8n;
- Make;
- Google Sheets;
- databases;
- PR dashboards;
- internal applications.

***

### Example multi-market monitoring input

```json
{
  "brands": [
    {
      "query": "\"Example Brand\"",
      "label": "Example Brand"
    }
  ],
  "languages": [
    "english",
    "portuguese"
  ],
  "countries": [
    "US",
    "BR"
  ],
  "timespanHours": 48,
  "maxRecordsPerQuery": 150,
  "dedupeTitles": true,
  "maxResults": 500
}
```

This creates four independent dimensions:

```text
Example Brand / english / US
Example Brand / english / BR
Example Brand / portuguese / US
Example Brand / portuguese / BR
```

***

### API

Run the Actor through the Apify API:

```bash
curl -s "https://api.apify.com/v2/acts/<YOUR_USERNAME>~brand-news-monitor/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "brands":[
      {"query":"\"Anthropic\"","label":"Anthropic"}
    ],
    "languages":["english"],
    "countries":[],
    "timespanHours":72,
    "maxResults":500
  }'
```

Replace:

```text
<YOUR_USERNAME>
<YOUR_APIFY_TOKEN>
```

with your Apify account values.

***

### Integrations

Use with:

- Apify API;
- Tasks;
- Schedules;
- webhooks;
- n8n;
- Make;
- Slack;
- Microsoft Teams;
- Google Sheets;
- databases;
- BI tools;
- internal applications;
- AI agents downstream.

***

### Pricing

This Actor uses **Pay Per Event**.

The code uses two custom billing events:

```text
actor-start
new-mention
```

#### `actor-start`

Called once after valid input has been accepted.

Invalid input is rejected before the billing gate opens.

#### `new-mention`

Charged per delivered `NEW_MENTION`.

The Actor does not charge `new-mention` for:

- first-run baseline articles;
- URLs already seen in that monitoring dimension;
- normalized titles already seen when `dedupeTitles=true`;
- rows without a usable URL;
- `BRAND_SUMMARY`;
- `RUN_SUMMARY`.

The **Pricing** tab on the Actor page is always the authoritative source for current prices.

***

### What is free

Free by design:

```text
first baseline
repeated article URLs
normalized-title duplicates
BRAND_SUMMARY
RUN_SUMMARY
```

A quiet scheduled run can therefore produce useful summaries without a `new-mention` event.

The configured start event can still apply.

***

### Cost control

Primary controls:

```text
brands
languages
countries
timespanHours
maxRecordsPerQuery
maxResults
maxRuntimeMs
```

#### Focused monitoring

Use:

- fewer brands;
- one language;
- one source country;
- a narrower GDELT query;
- a shorter window.

#### Broader monitoring

Multiple languages and countries multiply the number of independent dimensions and GDELT requests.

The Actor enforces a hard 40-dimension limit.

***

### Run health

Operational statistics are written to:

```text
STATS
```

in the default Key-Value Store.

Depending on the run, STATS can include:

- HTTP requests;
- retries;
- rate-limit responses;
- dimensions completed;
- dimensions failed;
- baseline dimensions;
- billable records;
- free records;
- source availability;
- quality alerts;
- runtime;
- caps;
- cost metrics.

***

### Honest limits

#### GDELT decides coverage

The Actor can only monitor articles that GDELT returns for the supplied query and filters.

No news index guarantees universal publisher coverage.

#### No article body

The Actor returns article metadata and the publisher URL, not the full publisher page.

#### Query quality matters

A common brand name can create unrelated mentions.

Use precise GDELT query syntax when necessary.

#### Exact normalized-title deduplication has tradeoffs

When enabled, two different publisher URLs with the same normalized title are treated as the same syndicated mention.

This can suppress a genuinely separate article that happens to use the identical headline.

#### URL deduplication uses the returned publisher URL

If the same underlying story is published under materially different URLs and does not share a normalized title, both can be treated as separate mentions.

#### The article read window is capped

`maxRecordsPerQuery` has a maximum of 250.

High-volume queries can therefore require shorter scheduling intervals or narrower filters.

#### GDELT APIs are rate limited

The Actor deliberately spaces requests and maintains a 40-dimension cap, but availability and quota behavior remain controlled by GDELT.

#### Brand × language × country state is independent

The same article can legitimately appear in multiple monitored dimensions and can be billable once in each independent dimension.

For example, monitoring an aggregate all-country dimension and a US-only dimension in separate Tasks creates different monitoring contracts.

#### No fuzzy syndication matching

The Actor does not use similarity models or embeddings to decide that two differently worded headlines are the same story.

#### No sentiment analysis

The Actor does not label coverage positive, negative, or neutral.

#### No AI in runtime

There is no LLM-generated summary, classification, or deduplication.

***

### FAQ

#### Do I need a GDELT account?

No.

#### Do I need a GDELT API key?

No for the public DOC 2.0 endpoint used here.

#### Does it use a browser?

No.

#### Can I monitor multiple brands?

Yes.

The total brand × language × country dimension count must be 40 or less.

#### What happens on the first run?

The current returned article identities are learned as free baseline state.

No historical article is emitted as `NEW_MENTION`.

#### Why did I receive no billable mention?

Possible reasons:

- this was the first baseline;
- no unseen URL appeared;
- title deduplication suppressed a syndicated duplicate;
- the result/runtime/billing cap stopped further delivery.

#### Can I monitor Portuguese news?

Yes.

Use:

```json
{
  "languages": [
    "portuguese"
  ]
}
```

#### Can I monitor Brazilian sources?

Yes.

Use:

```json
{
  "countries": [
    "BR"
  ]
}
```

#### Can I monitor all languages?

Yes.

Use:

```json
{
  "languages": []
}
```

#### Can I monitor all countries?

Yes.

Use:

```json
{
  "countries": []
}
```

#### Can I use advanced GDELT query syntax?

The Actor passes the brand query to GDELT and adds its own language/country filters.

Use GDELT-supported query syntax carefully.

#### How is a mention ID created?

A deterministic SHA-256 hash of the article URL is truncated to 16 hexadecimal characters.

#### Does a repeated URL get charged again?

No while its identity remains in that dimension's persistent state.

#### Can syndicated copies be suppressed?

Yes.

Keep:

```json
{
  "dedupeTitles": true
}
```

#### Is title deduplication fuzzy?

No.

It is deterministic normalized exact matching.

#### Are summaries charged?

No.

#### Can I schedule the Actor?

Yes.

#### What am I charged for?

The custom start event shown in Pricing plus genuinely new `NEW_MENTION` records delivered after baseline.

#### Can GDELT data be used commercially?

GDELT's published Terms of Use permit academic, commercial, and governmental use of its datasets without a dataset fee. Redistribution requires attribution to GDELT.

#### Is this affiliated with GDELT?

No.

This is an independent community Actor using the public GDELT DOC 2.0 API.

***

### Support

For bugs, questions, or requested fields:

```text
johnatan291303@gmail.com
```

You can also use the **Issues** tab on the Actor page.

***

### Part of the JM Forge suite

Also from the same developer:

- **ATS Hiring Signals Monitor** — persistent hiring-signal monitoring.
- **Steam Review Monitor & Player Feedback Alerts** — genuinely new Steam review monitoring.
- **NHTSA Recall, Complaint & Safety Spike Monitor** — stateful US vehicle-safety intelligence.

JM Forge Actors remain independent tools.

Use this Actor for stateful global news mentions and media-monitoring workflows.

# Actor input Schema

## `brands` (type: `array`):

One entry per brand: { "query": ""anthropic"", "label": "Anthropic" }. The query is passed to GDELT as-is (quote exact phrases). A bare string also works.

## `languages` (type: `array`):

GDELT sourcelang values (english, portuguese, spanish, german, french...). Each language is a separate monitored dimension. Empty = all languages in one dimension.

## `countries` (type: `array`):

GDELT sourcecountry values (US, BR, UK...). Each country multiplies the monitored dimensions. Empty = all countries.

## `timespanHours` (type: `integer`):

How far back each run looks. Keep it a bit larger than your schedule interval so nothing falls between runs — dedup guarantees no double charging.

## `maxRecordsPerQuery` (type: `integer`):

GDELT maxrecords per monitored dimension.

## `dedupeTitles` (type: `boolean`):

Optional second layer: a mention whose normalized title was already seen for this brand is not charged again (catches syndicated republications under new URLs). Deterministic exact match, no fuzzy logic.

## `maxResults` (type: `integer`):

Hard cap on charged NEW\_MENTION records. The run stops gracefully and keeps what it delivered.

## `maxRuntimeMs` (type: `integer`):

Hard time cap. GDELT asks for one request every 5 seconds, so ~40 monitored dimensions fit the default.

## `debug` (type: `boolean`):

Log pacing waits and per-brand decisions.

## Actor input object example

```json
{
  "brands": [
    {
      "query": "\"anthropic\"",
      "label": "Anthropic"
    }
  ],
  "languages": [
    "english"
  ],
  "countries": [],
  "timespanHours": 72,
  "maxRecordsPerQuery": 75,
  "dedupeTitles": true,
  "maxResults": 500,
  "maxRuntimeMs": 300000,
  "debug": false
}
```

# Actor output Schema

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

Default dataset containing NEW\_MENTION, BRAND\_SUMMARY, and RUN\_SUMMARY records.

## `stats` (type: `string`):

STATS record with requests, retries, billing counters, quality signals, runtime, caps, and operational metrics.

# 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 = {
    "brands": [
        {
            "query": "\"anthropic\"",
            "label": "Anthropic"
        }
    ],
    "languages": [
        "english"
    ],
    "countries": [],
    "timespanHours": 72,
    "maxRecordsPerQuery": 75,
    "dedupeTitles": true,
    "maxResults": 500,
    "maxRuntimeMs": 300000,
    "debug": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("johnatan029/brand-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 = {
    "brands": [{
            "query": "\"anthropic\"",
            "label": "Anthropic",
        }],
    "languages": ["english"],
    "countries": [],
    "timespanHours": 72,
    "maxRecordsPerQuery": 75,
    "dedupeTitles": True,
    "maxResults": 500,
    "maxRuntimeMs": 300000,
    "debug": False,
}

# Run the Actor and wait for it to finish
run = client.actor("johnatan029/brand-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 '{
  "brands": [
    {
      "query": "\\"anthropic\\"",
      "label": "Anthropic"
    }
  ],
  "languages": [
    "english"
  ],
  "countries": [],
  "timespanHours": 72,
  "maxRecordsPerQuery": 75,
  "dedupeTitles": true,
  "maxResults": 500,
  "maxRuntimeMs": 300000,
  "debug": false
}' |
apify call johnatan029/brand-news-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,johnatan029/brand-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/gvGqBdulbOuXcrF9r/builds/tAz9VVabeYediTwK3/openapi.json
