# Google News API – Monitoring, Pay Only for New Articles (`datarelay/google-news-api`) Actor

Monitor Google News for keywords, topics and publishers. One record per article across queries and countries, charges only for articles new since your last run, publisher URLs on request and a report of what may be missing.

- **URL**: https://apify.com/datarelay/google-news-api.md
- **Developed by:** [DataRelay](https://apify.com/datarelay) (community)
- **Categories:** News, AI, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.99 / 1,000 articles

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Google News API – Monitoring, Pay Only for New Articles

Monitor Google News for **keywords, topics and publishers**, in any country and language. Get one clean record per
article: headline, publisher, date, link and everything that found it. Schedule it, and **each run delivers and charges
only the articles that are new since the last one.**

### Why this Actor

- **Pay for articles you have not received, not for repeats.** Monitoring runs see mostly the same articles. With a sync
  key, the Actor remembers what it delivered: repeats are skipped and free, and a run with nothing new costs nothing, no
  start fee either. Works best with specific queries: see "Monitoring".
- **One record per article.** An article found by several queries, topics or countries is delivered and charged once,
  with `matchedQueries` and `matchedLocales` listing everything that found it.
- **An honest report of what may be missing.** Google returns at most ~100 results per search. The run report
  (`OUTPUT`) lists the searches that reached this limit, what failed and what was left out, so you know when to narrow a
  query.
- **Past the 100-result limit.** A search that reaches the limit is read again day by day, and a `from` / `to` period is
  always searched per day: up to ~100 articles per day, minus the overlap. No extra charge per search.
- **Alerts without extra tools.** A ready-made digest of the new articles, sent to Slack with one field, and an alarm when
  a query has far more articles than usual.
- **How far a story spread.** `storyPublishers` tells how many publishers of the feeds read carry the same story, mainly
  useful for topics.
- **Publisher URLs when you need them.** Google's feed has only redirect links. `resolveUrls` adds the address at the
  publisher as a separate add-on, charged only when it succeeds.

### Who uses it

- **Brand and competitor monitoring**: new mentions to Slack, e-mail or a spreadsheet through n8n, Make, Zapier or
  Apify integrations.
- **Media analysis and research**: the coverage of a topic per day, country or publisher.
- **AI agents and automations**: a documented input, predictable records and a run report for decisions.

### Quick start

```json
{
    "queries": ["electric vehicles"],
    "timeRange": "1d"
}
```

| Goal                               | Input                                                                                                                              |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| Monitor a brand, only new articles | `{"queries": ["\"Tesla\""], "timeRange": "1d", "syncKey": "brand-tesla", "maxArticles": 0}`                                        |
| Several countries                  | `{"queries": ["Rivian"], "locales": ["en-US", "en-GB", "de-DE"]}`                                                                  |
| Latest from a publisher            | `{"sites": ["reuters.com"], "timeRange": "1d"}`                                                                                    |
| A topic in selected publishers     | `{"queries": ["interest rates"], "sites": ["reuters.com", "ft.com"]}`                                                              |
| A section or the front page        | `{"topics": ["TECHNOLOGY", "TOP"], "timeRange": "any"}`                                                                            |
| A period, day by day               | `{"queries": ["offshore wind"], "from": "2026-10-01", "to": "2026-10-07", "maxArticles": 0}`                                       |
| With publisher URLs                | `{"queries": ["renewable energy"], "maxArticles": 20, "resolveUrls": true}`                                                        |
| Monitor without press releases     | `{"queries": ["Rivian"], "timeRange": "1d", "syncKey": "rivian", "excludeSites": ["prnewswire.com"]}`                              |
| Slack alerts with new articles     | `{"queries": ["\"Tesla\""], "timeRange": "1d", "syncKey": "brand-tesla", "slackWebhookUrl": "https://hooks.slack.com/services/…"}` |
| A topic by its address             | `{"feedUrls": ["https://news.google.com/topics/CAAq…?hl=en-US&gl=US&ceid=US:en"], "timeRange": "any"}`                             |
| The last 6 hours                   | `{"queries": ["oil price"], "timeRange": "6h"}`                                                                                    |
| More from a search at the limit    | `{"queries": ["Tesla"], "timeRange": "1d", "extraReadsAtCap": 2, "maxArticles": 0}`                                                |

### Input

| Field                              | What it does                                                                                                                          |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `queries`                          | Search queries, with Google News operators: `"exact phrase"`, `a OR b`, `-word`, `site:`, `when:`, `after:`.                          |
| `topics`                           | Sections: `TOP`, `WORLD`, `NATION`, `BUSINESS`, `TECHNOLOGY`, `ENTERTAINMENT`, `SPORTS`, `SCIENCE`, `HEALTH`.                         |
| `sites`                            | Publisher domains. Alone: the publisher's latest. With queries: every query in every publisher.                                       |
| `feedUrls`                         | Addresses of topics or publishers from news.google.com, in their edition or in every locale.                                          |
| `excludeSites`                     | Domains whose articles are not delivered or charged, subdomains included.                                                             |
| `locales`                          | Editions as language-country: `en-US`, `pl-PL`, `pt-BR`. Default `en-US`.                                                             |
| `timeRange`                        | `any`, or a number with `h`, `d` or `y`: `6h`, `1d`, `7d` (default), `90d`, `1y`.                                                     |
| `from`, `to`                       | A period instead of the range: `YYYY-MM-DD` (a UTC day) or ISO 8601. Dates are checked exactly.                                       |
| `splitByDay`                       | Search each day of a period, and read a search at Google's limit again day by day (time ranges up to 92 days). Default on.            |
| `extraReadsAtCap`                  | Read a search still at the limit 1–3 more times from other sessions. Mostly for ranges of a day or less. Default 0.                   |
| `maxArticles`                      | Per run, newest first; 0 = no limit. Default 100. With a sync key, the rest stays new for the next run.                               |
| `maxArticlesPerQuery`              | Per query or topic in each locale; 0 = no limit.                                                                                      |
| `onlyNew`, `syncKey`, `syncReset`  | Monitoring: see below.                                                                                                                |
| `resolveUrls`                      | Add the publisher's URL (paid add-on, two extra requests per article).                                                                |
| `spikeFactor`, `spikeMinArticles`  | The mention alarm under a sync key: see Monitoring. Default 3 times the usual level and at least 5 articles; `spikeFactor: 0` is off. |
| `slackWebhookUrl`                  | Send the digest to Slack: see Monitoring. Stored encrypted.                                                                           |
| `maxRunSecs`, `proxyConfiguration` | Time budget; Apify Proxy (default). Residential proxies are used only after Google blocks a request.                                  |

A query with its own date operator (`when:`, `after:`, `before:`) keeps it, and the run's time range does not apply to
it. At most 500 feeds per run.

#### Monitoring

Give a `syncKey` and schedule the run. The memory lives in your account, in the key-value store
`google-news-sync-<key>`, and holds only short hashes of article ids. You can add or change queries under the same key:
what was delivered is not charged again. An article is forgotten after 90 days without being found; the memory keeps the
latest 200,000. `syncReset` starts over. "New" means not delivered under this key, not necessarily just published.

**Old articles are not delivered as new.** After the first run under a key, an article published more than 24 hours before
the previous complete run is skipped and free, even if you were not shown it before (`OUTPUT.lateSkipped`). A run with a
`from` / `to` period and a query with its own date operator are exempt: they ask for those dates. So is the first run.

**Specific queries work best.** Google's list for a query depends on the IP that asks. A later run can still bring
articles from the last day that you were not shown earlier: measured in four later runs, `weather` over 7 days delivered
40, 1, 13 and 4, and `Tesla` over 3 days 4, 0, 8 and 0. Narrower queries reduce that. **The first run can be large**,
because it delivers everything found (708 articles for `weather` over 7 days): keep a `maxArticles` limit for it.

#### Digest and Slack

A run with new articles or a spike writes the record `DIGEST`: the articles by query, with publisher, age, how many
publishers carry the story, spikes first, and what may be missing. At most 30 articles are listed, then a count. Give an
incoming webhook in `slackWebhookUrl` and the same text goes to that channel. A run with nothing new sends nothing and
writes no record. `OUTPUT.digest` and `OUTPUT.slack` tell what happened; a failed message never fails the run.

#### Mention spikes

Under a sync key, the Actor counts delivered articles per query and publishing day. When today reaches `spikeFactor` times
the daily average of the last 14 days (at least `spikeMinArticles`, with 3 days of history), the query is in
`OUTPUT.spikes` and at the top of the digest, once a day. It counts what Google lists within its limits: a sign to look,
not a measure of coverage.

### Output

```json
{
    "id": "CBMiuAFBVV95cUxOTUJx…",
    "title": "Germany opens door to offshore wind returns as sector pressures grow",
    "source": { "name": "Reuters", "domain": "reuters.com" },
    "publishedAt": "2026-11-01T09:12:00.000Z",
    "googleNewsUrl": "https://news.google.com/rss/articles/CBMiuAFBVV95cUxOTUJx…?oc=5",
    "url": null,
    "urlStatus": "not_requested",
    "relatedArticles": [],
    "storyPublishers": 3,
    "storyUrl": null,
    "matchedQueries": ["offshore wind"],
    "matchedLocales": ["en-US", "en-GB"],
    "language": "en",
    "country": "US",
    "fetchedAt": "2026-11-02T04:30:00.000Z"
}
```

- `url` is `null` unless resolved; `urlStatus` tells why: `not_requested`, `resolved`, `failed` or
  `not_resolved_spending_limit`.
- `relatedArticles` is the other coverage Google groups with a story, mostly in topic feeds.
- `storyPublishers` is the number of publishers of the story among the feeds of this run, from Google's related coverage and
  identical headlines. It is an estimate of the spread, higher for topics than for searches, which have no related coverage.
- `storyUrl` is Google's Full Coverage page, when the feed links one (a few topic articles).
- The feed has **no article text, snippet or image**, and this Actor does not fetch them.
- The dataset has an `overview` and a `flat` view (CSV, spreadsheets).

#### Run report (`OUTPUT`)

Totals (`articles`, `returned`, `unique`, `duplicatesInRun`, `duplicatesSync`, `lateSkipped`, `excludedSites`, `outOfRange`, `invalid`, `notDelivered`,
`resolved`, `unresolved`), `stopReason` (`maxArticles`, `spending_limit`, `time_limit` or null), `feedStatuses`, per
feed `feeds` (query, locale, status, returned, unique, capped), `incomplete` (searches at Google's limit),
`otherLanguage` (editions Google answered in another language because it has no such edition), `notAvailable`, `spikes`,
`digest`, `slack` and `chargedEvents`.

### Measured

Beta on the Apify platform, 2026-11-02, Apify datacenter proxies, 256 MB. One day of measurements, so not yet a
long-term record.

| What                                             | Result                                                                           |
| ------------------------------------------------ | -------------------------------------------------------------------------------- |
| 53 runs, all feeds                               | 0 failed feeds, 0 HTTP 429, 0 items rejected by the parser                       |
| 1 search, 5 articles                             | 4 s                                                                              |
| 10 searches, 995 articles                        | 76 s                                                                             |
| Publisher URLs                                   | 50 of 50 resolved, ~2.5 s per URL                                                |
| Later runs of a query under a sync key           | see Monitoring                                                                   |
| A search at the limit read day by day, 7 days    | 729 articles instead of ~100, 65 s                                               |
| Extra reads at the limit (3 reads, small sample) | `Tesla` +33–46 % articles, `weather` +5–6 %                                      |
| Publishers per story                             | a topic: 4.2 on average; a search: 1.0, as search feeds have no related coverage |

### Pricing

Pay per event; platform usage and proxies are included.

| Event          | Price (FREE, BRONZE) | When                                                                            |
| -------------- | -------------------- | ------------------------------------------------------------------------------- |
| `run-start`    | $0.0045              | once per run, together with the first paid article                              |
| `article`      | $1.95 per 1,000      | delivered article: unique in the run and, with a sync key, not delivered before |
| `resolved-url` | $0.95 per 1,000      | publisher URL resolved (`resolveUrls`)                                          |

Higher plans pay less: `article` $1.50 (SILVER) and $0.99 (GOLD and above) per 1,000; `resolved-url` $0.75 and $0.60;
`run-start` $0.0035 and $0.003.

| Typical job (BRONZE)                    | Cost   |
| --------------------------------------- | ------ |
| 100 articles                            | $0.20  |
| 100 articles with publisher URLs        | $0.30  |
| Hourly monitor, 5 new articles in a run | $0.014 |
| Hourly monitor, nothing new in a run    | free   |

**You don't pay** for repeats under a sync key, late articles, duplicates, articles outside the dates, URLs that could not be resolved,
failed feeds or a run that delivers nothing (no start fee either).

### Limitations

- **Full Coverage pages cannot be read.** Google answered "This feed is not available" for each one tried. Such a URL in
  `feedUrls` is free and reported in `OUTPUT.notAvailable`; use `storyUrl` and `storyPublishers` instead.
- **Excluded publishers still take places in Google's limit of ~100**, because they are filtered after reading: a search full
  of them returns fewer articles. `-site:` in a query is not a way around it: Google then ignores the time range.
- **Not every article.** Google News decides what it lists: at most ~100 results per search, topic feeds 30–70, the front
  page ~40. There is no guarantee of completeness, and `OUTPUT.incomplete` flags searches at the limit.
- **Publishing dates come from Google**, and some articles carry only a day (shown as 07:00 UTC).
- **`after:` / `before:` are approximate at Google**, so the Actor reads one extra day and checks the dates itself. Those
  extra reads are free; `outOfRange` counts what they removed.
- **Older periods thin out**: Google lists less the further back you go.
- **The same query can list different articles from run to run**, above all at Google's limit of ~100 results: see
  "Monitoring".
- **Scheduled runs with one sync key should not overlap.** Parallel saves are merged, but an article found by two
  overlapping runs can be delivered twice.
- A language Google has no edition for falls back to US English: see `OUTPUT.otherLanguage`.

### FAQ

**Is it legal to use this data?** The Actor reads public Google News feeds, which need no account. Those feeds carry
Google's notice that they are meant for personal, non-commercial use in a feed reader. Headlines and links also belong to
their publishers. Check that your use fits these terms; this is not legal advice.

**Why are there no article texts?** Texts and images belong to the publishers. Resolve the URL and open the article.

**Why does a query return exactly 100 articles?** That is Google's limit per search. Use a narrower query, a shorter
time range or `from` / `to`.

**How do I get only new articles?** Set a `syncKey` and schedule the run.

### Not affiliated with Google

This is an independent Actor by DataRelay, not an official Google product or API.

### Usage statistics

The Actor sends anonymous run statistics to the developer (options, numbers of articles and statuses, Google request
counts, duration). Queries, publisher domains and your Apify user id are never sent, only keyed hashes, used to count
repeated queries and distinct users. No articles or account details are collected.

### Changelog

- 0.1 – first version.

# Actor input Schema

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

What to search for, with Google News operators if you like: `tesla`, `"electric truck"`, `tesla OR rivian`, `tesla -musk`. An article found by several queries is delivered and charged once. Give at least one of: queries, topics, sites. To read only topics or only publishers, leave this empty.

## `topics` (type: `array`):

Google News sections of each locale. `TOP` is the front page. Topic feeds have 30–70 articles chosen by Google.

## `sites` (type: `array`):

Publisher domains, e.g. `reuters.com`. Alone: the latest from the publisher. With queries: every query is searched in every publisher.

## `locales` (type: `array`):

Google News editions to read, e.g. `en-US`, `en-GB`, `pl-PL`, `de-DE`. The same article in several editions is delivered once. OUTPUT.otherLanguage lists editions that Google answered in another language (an edition it does not have).

## `feedUrls` (type: `array`):

Addresses of topics or publishers from news.google.com: `/topics/…`, `/publications/…`. A URL with `hl`, `gl` and `ceid` is read in that edition, otherwise in every locale. `/stories/…` (Full Coverage) pages are accepted, but Google answers most of them with "This feed is not available": see `OUTPUT.notAvailable`.

## `excludeSites` (type: `array`):

Articles from these domains and their subdomains are not delivered or charged, e.g. `example.com`.

## `timeRange` (type: `string`):

How old articles may be: `any`, or a number with `h`, `d` or `y`, e.g. `6h`, `1d`, `7d`, `90d`, `1y`. Ignored when `from` or `to` is set.

## `from` (type: `string`):

Start of the period: `YYYY-MM-DD` (UTC) or an ISO 8601 date and time. Overrides the time range.

## `to` (type: `string`):

End of the period, inclusive: `YYYY-MM-DD` (UTC) or an ISO 8601 date and time. Overrides the time range.

## `splitByDay` (type: `boolean`):

Google returns at most ~100 results per search. With `from`, every day of the period is searched on its own. With a time range of up to 92 days, a search that reaches the limit is read again day by day. No extra charge per search.

## `maxArticles` (type: `integer`):

Newest first. 0 = no limit. With monitoring, articles over the limit stay new for the next run.

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

Per query or topic in each locale. 0 = no limit.

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

Monitoring: deliver and charge only articles not delivered before under the sync key. For scheduled runs. Setting a sync key turns this on.

## `syncKey` (type: `string`):

Name of the memory of delivered articles, kept in your account (key-value store `google-news-sync-<key>`). You can change queries under the same key: articles already delivered are not charged again. Letters, digits and dashes, at most 40. An article not found for 90 days is forgotten; the memory holds the latest 200,000.

## `syncReset` (type: `boolean`):

Forget the delivered articles of the sync key before this run.

## `resolveUrls` (type: `boolean`):

Google News gives only its own redirect link (`googleNewsUrl`). This adds the publisher's address in `url`: a paid add-on per resolved URL, charged only when it succeeds, and slower (two requests per article). `urlStatus` says what happened.

## `extraReadsAtCap` (type: `integer`):

A search still at Google's limit is read this many more times, from other sessions. Google's list depends on the IP that asks, so this can find more articles. Mostly useful for a time range of one day or less. No extra charge per read.

## `spikeFactor` (type: `integer`):

With a sync key: report a query whose articles today are at least this many times its daily average of the last 14 days (needs 3 days of history). In `OUTPUT.spikes`, the digest and Slack. 0 = off.

## `spikeMinArticles` (type: `integer`):

Fewer articles today are never a spike.

## `slackWebhookUrl` (type: `string`):

Send the digest to Slack: an incoming webhook, `https://hooks.slack.com/services/…`. Sent only when a run has new articles or a spike. Stored encrypted.

## `maxRunSecs` (type: `integer`):

Stop early and keep what was delivered. 0 = until the run's timeout.

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

Apify Proxy (default) keeps runs reliable. With residential proxies selected, the run starts on datacenter proxies and uses residential only after Google blocks a request.

## Actor input object example

```json
{
  "queries": [
    "electric vehicles"
  ],
  "locales": [
    "en-US"
  ],
  "timeRange": "7d",
  "splitByDay": true,
  "maxArticles": 20,
  "maxArticlesPerQuery": 0,
  "onlyNew": false,
  "syncReset": false,
  "resolveUrls": false,
  "extraReadsAtCap": 0,
  "spikeFactor": 3,
  "spikeMinArticles": 5,
  "maxRunSecs": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

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

No description

## `digest` (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 = {
    "queries": [
        "electric vehicles"
    ],
    "locales": [
        "en-US"
    ],
    "maxArticles": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datarelay/google-news-api").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": ["electric vehicles"],
    "locales": ["en-US"],
    "maxArticles": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("datarelay/google-news-api").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": [
    "electric vehicles"
  ],
  "locales": [
    "en-US"
  ],
  "maxArticles": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call datarelay/google-news-api --silent --output-dataset

```

## MCP server setup

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

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/rxzbOG7FmCXBuHHhR/builds/7yGsgDHlBhTO9wjzS/openapi.json
