# Google News Scraper: Search, Top Stories, Topics & Local News (`winterlock/google-news-scraper`) Actor

Monitor Google News by keyword, top stories, topic section or place, in 84 country and language editions. Clean headlines, publisher name and site, UTC dates, related coverage, optional real article URLs, de-duplication across queries and an only-new-since-last-run mode. No login.

- **URL**: https://apify.com/winterlock/google-news-scraper.md
- **Developed by:** [Alex Burton](https://apify.com/winterlock) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.00 / 1,000 news 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

## Google News Scraper: Search, Top Stories, Topics & Local News

Monitor Google News for any keyword, brand, person, topic section or place, in any of Google's 84 country and language editions, and export the articles to JSON, CSV or Excel. Built for PR and brand monitoring, media research and news alerts: clean headlines, publisher name and website, UTC publish times, the other outlets covering the same story, and optionally each article's real URL on the publisher's site. No Google account, no API key, no browser.

One Actor, four jobs:

| Mode | What you get |
|---|---|
| **Search by keywords** | Articles matching your query, with Google News operators (`"exact phrase"`, `OR`, `-exclude`, `intitle:`, `site:`), a time range or exact dates, and an optional publisher filter |
| **Top stories** | The headline stories Google News is leading with in an edition, each with its related coverage |
| **Topic sections** | World, Nation, Business, Technology, Entertainment, Sports, Science, Health, or any other Google News topic by link |
| **Local news for a place** | The local section Google News keeps for a city, region or country |

### Why use this one

- **Monitoring mode.** Turn on *Only articles not seen in earlier runs* and schedule the Actor. It remembers what each query, topic or place has already delivered, returns only new articles, and you pay only for those.
- **Real article URLs, when you want them.** Google News links are redirects. Turn on *Resolve publisher article URLs* and each row gets the article's actual address on the publisher's site, looked up through the same calls Google's own redirect page makes. It is a separate, clearly priced add-on, charged only for URLs actually found; nothing is ever guessed.
- **More than 100 results per search.** Google caps every search at 100 articles. *Split by day* runs the search once per day of your date range, so a month of coverage can return up to about 3,000 articles.
- **Date filters you can trust.** Google applies `when:`, `after:` and `before:` loosely, and once `site:` is in the query it sometimes ignores them entirely (in testing, a past-24-hours `site:` search came back with articles from 2009). Every date window is enforced again on each article's own publish time, and the log says how many out-of-range articles were dropped.
- **Clean, joinable rows.** The " - Publisher" suffix Google appends to every headline is moved into `publisher`; `publisherUrl` and `publisherDomain` come from Google's source data; times are ISO-8601 UTC.
- **One article, one row, one charge.** An article that matches several queries, or appears in several editions, is saved once.
- **Places are checked.** Google silently answers an unknown place with national US headlines. This Actor detects that, says so in the log, and saves nothing for that place instead of billing you for the wrong news.

### How to use it

1. Choose **What to scrape**.
2. Add **Search queries**, **Topics** or **Locations**.
3. Pick one or more **Editions** (`US:en`, `GB:en`, `DE:de`, `FR:fr`, `IN:hi`...). Each runs separately; duplicates across editions are dropped.
4. For searches, set a **Time range** or **From/To dates**, and optionally **Only these publishers**.
5. Click **Start**, then download the results or connect the dataset to Google Sheets, Slack, Zapier or Make.

#### Example input: daily brand monitor

```json
{
  "mode": "search",
  "searchQueries": ["\"OpenAI\"", "\"Anthropic\" -job"],
  "editions": ["US:en", "GB:en"],
  "timeRange": "1d",
  "onlyNewArticles": true,
  "resolveOriginalUrls": true
}
```

#### Example input: a month of coverage from two outlets

```json
{
  "mode": "search",
  "searchQueries": ["tesla"],
  "sites": ["reuters.com", "bbc.co.uk"],
  "dateFrom": "2026-09-01",
  "dateTo": "2026-09-30",
  "splitByDay": true,
  "maxArticlesPerSearch": 1000
}
```

#### Example input: German business and technology headlines

```json
{
  "mode": "topic",
  "topics": ["BUSINESS", "TECHNOLOGY"],
  "editions": ["DE:de"]
}
```

#### Example input: local news for three cities

```json
{
  "mode": "location",
  "locations": ["Chicago", "Austin, TX", "Munich"],
  "editions": ["US:en"]
}
```

### Output

Every row is one article (`"type": "article"`). The `mode`, `query`, `googleQuery`, `topic`, `location` and `edition` fields say where it was found; `position` is its place in Google's list.

**Top story with related coverage and a resolved URL**

```json
{
  "type": "article",
  "title": "Trump borrows from far right to blame unrest in France on immigration",
  "publisher": "The Guardian",
  "publisherUrl": "https://www.theguardian.com",
  "publisherDomain": "theguardian.com",
  "publishedAt": "2026-10-19T22:49:00Z",
  "originalUrl": "https://www.theguardian.com/us-news/2026/oct/19/trump-france-protests",
  "googleNewsUrl": "https://news.google.com/rss/articles/CBMieEFVX3lxTFB0bnZRYWwyOWhycjFR...?oc=5",
  "articleId": "CBMieEFVX3lxTFB0bnZRYWwyOWhycjFR...",
  "relatedCount": 4,
  "relatedArticles": [
    {
      "title": "Opinion | The French Fantasy Is Coming to an End",
      "publisher": "The New York Times",
      "googleNewsUrl": "https://news.google.com/rss/articles/CBMieEFVX3lxTE9PeGtmanU2WTVh...?oc=5",
      "articleId": "CBMieEFVX3lxTE9PeGtmanU2WTVh..."
    },
    {
      "title": "France in turmoil after riots and looting: What we know",
      "publisher": "Reuters",
      "googleNewsUrl": "https://news.google.com/rss/articles/CBMingFBVV95cUxQdnU5M25aUmFw...?oc=5",
      "articleId": "CBMingFBVV95cUxQdnU5M25aUmFw..."
    }
  ],
  "fullCoverageUrl": null,
  "position": 1,
  "mode": "topStories",
  "query": null,
  "googleQuery": null,
  "topic": null,
  "location": null,
  "edition": "US:en",
  "language": "en-US",
  "country": "US",
  "feedTitle": "Top stories - Google News"
}
```

**Search result**

```json
{
  "type": "article",
  "title": "Tesla asks shareholders to re-elect Musk, Denholm and Straubel at December annual meeting",
  "publisher": "Reuters",
  "publisherUrl": "https://www.reuters.com",
  "publisherDomain": "reuters.com",
  "publishedAt": "2026-10-19T19:44:40Z",
  "originalUrl": null,
  "relatedCount": 0,
  "relatedArticles": [],
  "position": 2,
  "mode": "search",
  "query": "tesla",
  "googleQuery": "tesla site:reuters.com when:7d",
  "edition": "US:en"
}
```

`fullCoverageUrl` is set when Google links a story to its "See more headlines & perspectives" page.

### Editions

Use `COUNTRY:language`. A country with a single edition can be given alone (`DE`).

`AE:ar` `AR:es-419` `AT:de` `AU:en` `BD:bn` `BE:fr` `BE:nl` `BG:bg` `BR:pt-419` `BW:en` `CA:en` `CA:fr` `CH:de` `CH:fr` `CL:es-419` `CN:zh-Hans` `CO:es-419` `CU:es-419` `CZ:cs` `DE:de` `EG:ar` `ES:es` `ET:en` `FR:fr` `GB:en` `GH:en` `GR:el` `HK:zh-Hant` `HU:hu` `ID:id` `IE:en` `IL:en` `IL:he` `IN:bn` `IN:en` `IN:hi` `IN:ml` `IN:mr` `IN:ta` `IN:te` `IT:it` `JP:ja` `KE:en` `KR:ko` `LB:ar` `LT:lt` `LV:en` `LV:lv` `MA:fr` `MX:es-419` `MY:en` `MY:ms` `NA:en` `NG:en` `NL:nl` `NO:no` `NZ:en` `PE:es-419` `PH:en` `PK:en` `PL:pl` `PT:pt-150` `RO:ro` `RS:sr` `RU:ru` `SA:ar` `SE:sv` `SG:en` `SI:sl` `SK:sk` `SN:fr` `TH:th` `TR:tr` `TW:zh-Hant` `TZ:en` `UA:ru` `UA:uk` `UG:en` `US:en` `US:es-419` `VE:es-419` `VN:vi` `ZA:en` `ZW:en`

Google falls back to another edition without warning when given a code it does not know, so codes outside this list are refused before the run starts.

### Pricing

Pay only for results:

| Result | Price |
|---|---|
| Article | $6.00 per 1,000 |
| Publisher article URL resolved (optional add-on, charged only when a URL is found) | $4.00 per 1,000 |

So 1,000 articles cost $6.00 without URL resolution, or $10.00 with a resolved URL on every one. The add-on costs more because finding one article's URL means downloading Google's article page (around 120 KB compressed), while a whole feed of up to 100 articles is one request of about 30 KB.

Set a maximum spend per run in the run options and the Actor stops cleanly when it is reached.

### Limits to know about

These come from Google News, not from this Actor:

- **100 articles per search.** Google's search feed has no further pages. Use *Split by day* with a date range to go past it. Topic and local feeds hold about 70 articles, top stories about 35.
- **Without a date, Google decides how far back a search goes**, usually a few days to a week for busy subjects.
- **Day boundaries are Google's.** For the US edition `after:2026-09-01` starts at midnight US Pacific time. The Actor's own date check allows 12 hours either side so it does not drop articles near midnight.
- **No snippets or article text.** The feed's description holds only the headline again, the publisher and related links, so there is no snippet field. Use `originalUrl` to fetch article text with a separate tool.
- **Publish times are Google's**, which for some outlets is when Google picked the article up.
- **URL resolution can fail for some articles.** Those keep `originalUrl` empty and are not charged the add-on. If Google stops answering lookups altogether, the Actor turns resolution off for the rest of the run and says so in the log.
- **Rate limits.** Google limits requests per IP address. Feeds are light (one request per query, topic or place per edition), but URL resolution is one request per article. If the log shows HTTP 429 or 503, turn on Apify Proxy.
- **Google's terms.** Google News's `robots.txt` asks crawlers not to fetch its RSS feeds (`/rss/`) or article pages, and the feeds carry a notice limiting them to personal feed-reader use. Make sure your use of the data is appropriate.

### FAQ

**Why are the article links on news.google.com?** That is what Google News publishes: every link is a redirect through Google. Turn on *Resolve publisher article URLs* to get the publisher's own URL in `originalUrl`.

**How do I get alerts for new articles only?** Turn on *Only articles not seen in earlier runs*, save the input as a task and schedule it (hourly or daily). Each run returns only articles that query has not delivered before; connect the dataset to Slack or email for alerts.

**Which search operators work?** Quoted phrases, `OR`, `-word`, `intitle:`, `site:`, `when:` (`1h`, `12h`, `1d`, `7d`, `30d`, `1y`), `after:` and `before:` with `YYYY-MM-DD` dates. A date operator written in the query takes precedence over the *Time range* field.

**Why did a place return nothing?** Google News only keeps local sections for places it knows. Use the spelling Google News uses (for example *New York*, *Munich*, *Austin*); the log names any place it did not recognise.

**Can I use a topic that is not in the list?** Yes. Open the topic on news.google.com and paste its address (`https://news.google.com/topics/...`) into *Topics*.

**Do I need a Google account or API key?** No.

### Feedback

Found a bug or need a field that is missing? Open an issue on the Actor's **Issues** tab.

# Actor input Schema

## `mode` (type: `string`):

Search Google News by keywords, read the top stories, read topic sections (Business, Technology...), or read local news for a place.

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

For Search. One query per line. Google News operators work: "exact phrase", OR, -exclude, intitle:word, site:example.com, when:7d, after:2026-01-01, before:2026-02-01.

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

For Topic sections. WORLD, NATION, BUSINESS, TECHNOLOGY, ENTERTAINMENT, SPORTS, SCIENCE or HEALTH, or paste a news.google.com/topics/... link for any other topic.

## `locations` (type: `array`):

For Local news. City, region or country names as Google News knows them: Chicago, New York, Munich, Texas. A place Google does not know is reported in the log and skipped, not billed.

## `editions` (type: `array`):

Google News editions to read, as COUNTRY:language codes: US:en, GB:en, IN:en, DE:de, FR:fr, ES:es, BR:pt-419, JP:ja and 76 more (see README). Each query, topic or place runs once per edition; an article found in two editions is saved once.

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

For Search. How far back to look. Ignored when a From or To date is set, or when a query has its own when:/after:/before:.

## `dateFrom` (type: `string`):

For Search. YYYY-MM-DD, inclusive. Overrides Time range.

## `dateTo` (type: `string`):

For Search. YYYY-MM-DD, inclusive. Leave empty for up to today.

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

Google returns at most 100 articles per search. With a From date set, this runs the search once per day (newest day first), so a month can return up to about 3,000 articles. One request per day.

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

For Search. Limit results to these websites, for example reuters.com or bbc.co.uk. Several sites are combined with OR in one search.

## `maxArticlesPerSearch` (type: `integer`):

For Search. Per query and edition. Google serves up to 100 per search; with Split by day up to 100 per day.

## `maxTopStories` (type: `integer`):

For Top stories. The feed holds about 30 to 40 stories.

## `maxArticlesPerTopic` (type: `integer`):

For Topic sections. Per topic and edition; a topic feed holds about 70 articles.

## `maxArticlesPerLocation` (type: `integer`):

For Local news. Per place and edition; a local feed holds up to about 70 articles.

## `includeRelatedCoverage` (type: `boolean`):

For clustered stories Google lists up to four other outlets covering the same story. Adds them to the article's row (title, publisher, link) at no extra cost.

## `resolveOriginalUrls` (type: `boolean`):

Google News links are redirects. On, each article's real URL on the publisher's site is looked up (one extra request per article plus one per 20) and charged as a separate event, only when found. Off, originalUrl stays empty.

## `onlyNewArticles` (type: `boolean`):

Remembers which articles each query, topic or place has already delivered, and on later runs returns only new ones. Schedule the Actor to get a feed of new coverage and pay only for what is new.

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

Stop the run after saving this many articles. Leave empty for no limit.

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

Only matters when resolving publisher URLs, which takes one request per article. Keep it low to stay under Google's rate limits.

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

Not needed for most runs. If the log shows HTTP 429 or 503 from Google, turn on Apify Proxy. Apify Proxy is used with datacenter IPs; residential groups are ignored.

## Actor input object example

```json
{
  "mode": "search",
  "searchQueries": [
    "artificial intelligence"
  ],
  "topics": [
    "TECHNOLOGY"
  ],
  "locations": [
    "Chicago"
  ],
  "editions": [
    "US:en"
  ],
  "timeRange": "1d",
  "splitByDay": false,
  "maxArticlesPerSearch": 100,
  "maxTopStories": 100,
  "maxArticlesPerTopic": 100,
  "maxArticlesPerLocation": 100,
  "includeRelatedCoverage": true,
  "resolveOriginalUrls": false,
  "onlyNewArticles": false,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (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": [
        "artificial intelligence"
    ],
    "topics": [
        "TECHNOLOGY"
    ],
    "locations": [
        "Chicago"
    ],
    "editions": [
        "US:en"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("winterlock/google-news-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 = {
    "searchQueries": ["artificial intelligence"],
    "topics": ["TECHNOLOGY"],
    "locations": ["Chicago"],
    "editions": ["US:en"],
}

# Run the Actor and wait for it to finish
run = client.actor("winterlock/google-news-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 '{
  "searchQueries": [
    "artificial intelligence"
  ],
  "topics": [
    "TECHNOLOGY"
  ],
  "locations": [
    "Chicago"
  ],
  "editions": [
    "US:en"
  ]
}' |
apify call winterlock/google-news-scraper --silent --output-dataset

```

## MCP server setup

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