# News & Brand Monitoring Scraper (`eiv/news-monitoring-scraper`) Actor

Monitor any brand, competitor or topic across Google News in any country. Headline, outlet, timestamp and coverage-breadth stats per query - plus optional resolution of Google's redirect links into the publisher's own URL, which most scrapers cannot do. No API key.

- **URL**: https://apify.com/eiv/news-monitoring-scraper.md
- **Developed by:** [Eimantas V](https://apify.com/eiv) (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 $0.20 / 1,000 article founds

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

## News & Brand Monitoring Scraper

Track any brand, competitor or topic across Google News — in any country, with the coverage stats that tell you whether something is a story or just a beat reporter.

```
"tesla"    100 articles   51 outlets   15.5/day   Electrek:12, Not a Tesla App:11, Yahoo Finance:8
"openai"   100 articles   43 outlets   14.5/day   OpenAI:15, TechCrunch:10, Bloomberg:6
"rivian"   100 articles   47 outlets   14.6/day   Yahoo Finance:12, eletric-vehicles:10

[Reuters]  Pressured by Tesla, European regulators keep 'Full Self-Driving' safety review open
[Forbes]   Tesla Headlights Are Illegally Bright, Recall Says
```

**300 articles across three queries in 1.2 seconds.** No API key, no login, no browser.

***

### It gives you the publisher's actual link

Google News hands out redirect addresses — `news.google.com/rss/articles/CBMi…` — which open fine in a browser and are useless to anything else. Most scrapers pass them straight through.

Older ones could be base64-decoded; these cannot, and following the link doesn't help because Google does the redirect in the browser. This Actor uses the same call the page itself makes, and turns them into real links:

```
insideevs.com     https://insideevs.com/reviews/798129/rivian-r2-first-drive-review/
motortrend.com    https://www.motortrend.com/reviews/2027-rivian-r2-real-world-range-test/
edmunds.com       https://www.edmunds.com/car-news/2027-rivian-r2-performance-launch-package/
```

It costs two extra requests and about 600 KB per article, so it's **off by default and billed separately**. Turn it on when you need to fetch, archive or attribute the articles; leave it off when the headline and outlet are enough.

***

### Outlets, not article counts

`distinctPublishers` is the number that tells you whether something is happening. Ten pieces from one outlet is a beat reporter; ten outlets carrying it is a story. Every summary row also carries `topPublishers` with counts, and `articlesPerDay` measured across the span the articles actually cover — not the window you asked for, so a 30-day search that returned one busy day reports that day's intensity rather than a thirtieth of it.

***

### What you get

**Per article** — `title` (outlet suffix removed), `publisher`, `publishedAt`, **`ageHours`**, `position`, `googleNewsUrl`, and with resolution on **`articleUrl`** + `publisherDomain` + `resolutionStatus`.

**Per query** — `articlesFound`, **`distinctPublishers`**, `topPublishers`, `articlesPerDay`, oldest and newest article, resolution counts, duplicates.

***

### Who this is for

- **PR and comms** — who covered us this week, how widely, and how fast it spread.
- **Competitive intelligence** — one run, one query per rival, weekly.
- **Investors and analysts** — coverage volume and breadth per ticker or company.
- **Content teams** — `site:` a competitor's domain to see everything they publish, which is exactly what a bare `site:` query is good for.

***

### Input

```json
{
  "queries": ["\"acme corp\"", "\"acme corp\" OR acmecorp -recall"],
  "country": "US",
  "timeWindow": "7d",
  "resolveArticleUrls": false
}
```

Google News search syntax works: quote a phrase, combine with `OR`, exclude with `-`, restrict with `site:reuters.com`.

| Option | Default | Notes |
|---|---|---|
| `country` | `US` | Each edition carries different outlets |
| `language` | follows country | DE→de, JP→ja, BR→pt |
| `timeWindow` | `7d` | 1h, 24h, 7d, 30d, 1y, any |
| `resolveArticleUrls` | `false` | Real publisher links; see below |
| `maxResolvedPerQuery` | `25` | Caps the expensive part |
| `maxArticlesPerQuery` | `100` | Google's own ceiling |
| `deduplicateAcrossQueries` | `true` | Same story under two queries counts once |

***

### Five things worth knowing

Each was found by running against live data.

**Google's links are not the publisher's links, and they cannot be decoded.** The modern ids decode to an opaque `AU_yqL…` blob, and following the URL returns HTTP 200 still on news.google.com because the redirect happens client-side. Resolution works by reading the signature and timestamp from the article page and calling the endpoint that page calls — 12 of 12 resolved in testing. The tokens sit **99.7% of the way into a 590 KB page**, a `Range` header is ignored, and the search listing carries no signatures to amortise against, so it genuinely costs one full page per article. That is why it is opt-in, capped per query, and charged only when it succeeds.

**`site:` does not intersect with your keyword — quote it.** `site:reuters.com tesla` reads like "Reuters articles about Tesla" and returns Reuters' recent output instead. Measured across 100 results each: `tesla` alone put the word in **104 of 104** headlines, `site:reuters.com tesla` in **15 of 100**, and `site:reuters.com "tesla"` in **71 of 100**. Word order makes no difference and `AND` does not help. Quote the keyword. The Actor warns when it sees an unquoted one rather than rewriting your query, because narrowing a search on your behalf is not its business.

**A feed stops at about 100 articles.** That is Google's limit, not a setting. Queries that come back full are flagged `truncated`, and the way past it is a narrower window or a narrower query — `"acme" when:24h` run daily beats `"acme" when:30d` run monthly.

**The outlet is appended to every headline, and cutting at the last dash mangles real ones.** `Tesla Q3 - what it means - Reuters` and `Rolls-Royce lands deal - BBC` both contain dashes that belong. The `<source>` tag says exactly what to remove, so the suffix comes off only when it matches the outlet.

**Only Google's own time windows work.** Anything else goes into the query as words, so `last week` would be *searched for* rather than applied, and the run would quietly return articles containing that phrase. Unrecognised values are rejected with a warning and fall back to 7 days.

***

### Output

```json
{
  "recordType": "article",
  "query": "\"rivian\"",
  "title": "Rivian R2 First Drive Review",
  "publisher": "InsideEVs",
  "publishedAt": "2026-08-12T18:46:00.000Z",
  "ageHours": 6.5,
  "position": 1,
  "googleNewsUrl": "https://news.google.com/rss/articles/CBMi...",
  "articleUrl": "https://insideevs.com/reviews/798129/rivian-r2-first-drive-review/",
  "publisherDomain": "insideevs.com",
  "resolutionStatus": "RESOLVED"
}
```

Three ready-made views: **Articles**, **Coverage summary** and **Resolved links**. Set `flattenOutput: true` for CSV.

***

### Honest limits

- **No article body, author or sentiment.** This reads Google's index, not the articles. Pair it with a content scraper on the resolved URLs if you need the text.
- **No share counts or reach figures.** `distinctPublishers` is breadth of coverage, not audience size, and this Actor will not invent an audience number.
- **Google decides what is in the index**, including which outlets and how far back. Two runs minutes apart can differ.
- **`articleUrl` is null unless resolution ran and succeeded** — never a guess. `resolutionStatus` says which of `RESOLVED`, `NOT_REQUESTED`, `NO_TOKENS` or `FAILED` applies, and every article always keeps a working `googleNewsUrl`.
- **Failed queries, duplicate articles and failed resolutions are never charged.**

***

### Pricing

| Event | Price | When |
|---|---|---|
| Actor start | $0.005 | Once per run |
| Query monitored | $0.004 | Per query, including the coverage summary |
| Article found | $0.0002 | Per article |
| Publisher URL resolved | $0.0015 | Only when resolution succeeds |

**$0.20 per 1,000 articles** without resolution. A daily 10-query watch costs about **$0.25 a run**. Mention and Brand24 start at $99–149 a month.

***

### Tips

- **Run `24h` daily rather than `7d` weekly.** You stay under the 100-article ceiling and get the same coverage with timestamps you can trend.
- **Diff on `googleNewsUrl` between runs** to get only what is new since yesterday.
- **Watch `distinctPublishers`, not `articlesFound`.** A jump in outlets is a story breaking; a jump in articles from the same outlet is not.
- **Add a `-yourbrand` exclusion to a competitor query** to strip out the comparison pieces you already know about.
- **Resolve only the top 10.** `position` reflects what Google considers the lead story, so the first handful are usually the ones worth reading in full.

# Actor input Schema

## `queries` (type: `array`):

One per line. Google News search syntax works: quote a phrase ("acme corp"), combine with OR, exclude with a minus, restrict to an outlet with site:reuters.com. If you combine site: with a keyword, quote the keyword — site:reuters.com "tesla" — because unquoted it is barely weighted and you get the outlet's recent output instead. Measured: 15 of 100 headlines matched unquoted, 71 of 100 quoted.

## `sourceDatasetId` (type: `string`):

Read queries from an existing dataset instead of typing them — for example the keywords found by a keyword research run.

## `sourceDatasetField` (type: `string`):

Which field on the source dataset holds the query.

## `country` (type: `string`):

ISO code such as US, GB, DE, JP. Google News runs a separate edition per country, and each carries different outlets — the German edition is not the American one translated.

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

Two-letter code. Left empty it follows the country: DE gives German, JP Japanese, BR Portuguese.

## `timeWindow` (type: `string`):

How far back to look. Only Google's own windows work; anything else would be searched for as words rather than read as a filter.

## `resolveArticleUrls` (type: `boolean`):

Turn Google's redirect links into the publisher's own address. Costs two extra requests and about 600 KB per article, because the tokens Google needs sit at the very end of a full article page. Leave off when the headline and outlet are enough.

## `maxResolvedPerQuery` (type: `integer`):

Caps the expensive part. Articles beyond the cap keep their Google News link and are marked NOT\_REQUESTED. Ignored unless resolution is on.

## `maxArticlesPerQuery` (type: `integer`):

Google News caps a feed at roughly 100 articles regardless. Queries that come back full are flagged truncated.

## `deduplicateAcrossQueries` (type: `boolean`):

Monitoring a brand and its product usually returns the same story twice. On, each story is emitted once and charged once; off, repeats are kept and marked isDuplicate.

## `includeQuerySummary` (type: `boolean`):

Add one rollup record per query: distinct outlets, top outlets, date range and articles per day. Not billed as an article.

## `maxConcurrency` (type: `integer`):

Queries processed in parallel.

## `requestTimeoutSecs` (type: `integer`):

Per-request timeout.

## `maxRetries` (type: `integer`):

Retries for connection resets and 5xx responses.

## `flattenOutput` (type: `boolean`):

Emit flat dot-notation columns. Mainly affects the top-outlets list on summary rows.

## `proxyConfiguration` (type: `object`):

Optional. The feed itself is a public RSS endpoint and does not block; a proxy mainly matters when resolving many publisher URLs in one run.

## Actor input object example

```json
{
  "queries": [
    "\"artificial intelligence\""
  ],
  "sourceDatasetField": "query",
  "country": "US",
  "timeWindow": "7d",
  "resolveArticleUrls": false,
  "maxResolvedPerQuery": 25,
  "maxArticlesPerQuery": 100,
  "deduplicateAcrossQueries": true,
  "includeQuerySummary": true,
  "maxConcurrency": 4,
  "requestTimeoutSecs": 45,
  "maxRetries": 2,
  "flattenOutput": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Article records carry recordType 'article'; rollups carry 'query-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 = {
    "queries": [
        "\"artificial intelligence\""
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("eiv/news-monitoring-scraper").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 = { "queries": ["\"artificial intelligence\""] }

# Run the Actor and wait for it to finish
run = client.actor("eiv/news-monitoring-scraper").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 '{
  "queries": [
    "\\"artificial intelligence\\""
  ]
}' |
apify call eiv/news-monitoring-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,eiv/news-monitoring-scraper"
        }
    }
}

```

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/xGhiajCYE82BkfEyv/builds/Iny2tj7q2W72LpPg6/openapi.json
