# Google News Scraper — News by Query, Exact Limit, No Start Fee (`steadyfetch/google-news-rss-scraper`) Actor

Type a search query and get Google News as rows — the headline, the Google News link, Google's own article id, the publication time as a real ISO timestamp, the publisher and their site, and how many outlets carried the story. From $0.80/1,000 articles, exact limit, no start fee.

- **URL**: https://apify.com/steadyfetch/google-news-rss-scraper.md
- **Developed by:** [Steadyfetch Team](https://apify.com/steadyfetch) (community)
- **Categories:** News, AI, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 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?

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

## Google News Scraper — News by Query, Exact Limit, No Start Fee

**Click Start with nothing set** and the run returns a small built-in sample — one query, ten articles — so you see the output shape before you spend anything, at no result fee. A box you *did* set and then left blank is a different thing and is answered as one: that entry is refused before anything is fetched, on one row naming the field, and nothing is charged for it.

**Using an AI agent?** Pin this actor in Apify's MCP server with one link: `https://mcp.apify.com?tools=steadyfetch/google-news-rss-scraper`

- **Actor id:** `steadyfetch/google-news-rss-scraper`
- **Input:** `{ "queries": ["electric vehicles"] }` — the one field you have to set. Or `{ "topics": ["TECHNOLOGY"] }` for a whole Google News section, with no query at all.
- **Cap the bill:** set `maxTotalChargeUsd` on the run (a run option, not Actor input), e.g. `0.50` — the run stops when it reaches it.
- **Your cap is the cap.** `maxItems` is exact and covers the whole run. Ask for 10 and you get 10 rows, not 100 and a bill for the other 90. There is one number in this actor and it is the one you set. The run page reconciles against that number and nothing else — articles your account already had are counted beside it ("10 more you already had were skipped, not charged"), never added to what you asked for.

**Priced from $0.80 per 1,000 articles** on the cheapest paid tier, $3.20 per 1,000 on the Apify free plan, platform usage included, **nothing charged for starting a run**. You are charged only when a row lands in your dataset: a query that matched nothing, a feed Google would not serve, and every article a limit or the run clock stopped us from collecting all cost $0.

### What one row looks like

A real delivered row, built by this actor's own parser from a harvested Google News feed:

```json
{
  "target": "openai",
  "targetKind": "query",
  "title": "AI agents being tested by OpenAI involved in cyber-attack on another service, say researchers",
  "titleWithSource": "AI agents being tested by OpenAI involved in cyber-attack on another service, say researchers - The Guardian",
  "googleNewsUrl": "https://news.google.com/rss/articles/CBMilwFBVV95cUxPUHZKUnc5TTdXbm1ZSmFOMkFkVTln…?oc=5",
  "guid": "CBMilwFBVV95cUxPUHZKUnc5TTdXbm1ZSmFOMkFkVTln…",
  "publishedAt": "2026-09-11T23:56:00.000Z",
  "publishedAtRaw": "Fri, 11 Sep 2026 23:56:00 GMT",
  "publisherName": "The Guardian",
  "publisherHomeUrl": "https://www.theguardian.com",
  "relatedArticleCount": 2,
  "language": "en",
  "country": "US",
  "timeWindow": null,
  "status": "delivered",
  "charged": true
}
```

The two long Google identifiers are trimmed with `…` for this page; a real row carries them in full. Every column is explained in the table below, and a row that could not be delivered carries the same columns with `null` in them, plus a `status` saying why — and no result fee.

### What you get

One row per article, one column set whichever door it came through — a search query, a Google News topic section, a place, or the top stories. (Each query or section also gets one row of its own; see **One extra row per query**, below.)

| column | what it is |
|---|---|
| `target` · `targetKind` | the query, topic or place that produced this row, and which kind it was |
| `title` | the headline, with the publisher suffix Google appends removed |
| `titleWithSource` | the headline exactly as Google publishes it, publisher suffix and all |
| `googleNewsUrl` | the article's link on Google News — see **About the link**, below |
| `guid` | Google's stable identifier for the article. It is what your account's memory keys on, so the same article is never delivered twice — unless the run's API token cannot open key-value stores, which the run page and the first row both say |
| `publishedAt` | when it was published, ISO-8601 UTC — a real timestamp, parsed, never a relative phrase like "2 hours ago" and never in the publisher's own language |
| `publishedAtRaw` | the same date exactly as Google published it, so you can check our parse |
| `publisherName` · `publisherHomeUrl` | who published it, and their site's home address — both come from Google's own `<source>` field and are present on every article we have measured |
| `relatedArticleCount` | how many other outlets Google grouped under this story |
| `language` · `country` · `timeWindow` | the settings this row was fetched under, on the row, so a dataset from several runs is still readable |
| `charged` · `chargedEvents` | whether this row was billed, and by which event. No row bills two. |
| `status` · `statusReason` | what happened, in a sentence, on every row including the ones that cost nothing |

### One extra row per query, and it is where the Query check lives

Alongside the article rows, **every query and every topic section you ask for gets one row of its own** — so a run of three queries returns your articles plus three of these, and a buyer counting rows should expect them.

That row says how many articles Google News is carrying for the query, how many were delivered, how many your account already had, and whether the **Query check** was charged for it. It is the only row that ever carries a Query check, and no row bills two events.

It exists for a plain reason: the check is charged per query, not per article, so it needs a row of its own. An all-repeat query has no article row for it to ride on, and a charge with no row behind it is a charge that cannot be reconciled from your dataset — which is the one thing every actor on this shelf promises you can do.

### About the link

**`googleNewsUrl` is the article's Google News link, not the publisher's own URL, and this actor does not pretend otherwise.**

Google News publishes every article behind an opaque redirect of its own. Turning one of those into a publisher URL is not a lookup — it is a second request per article against an undocumented endpoint that Google changes, and on the day this actor was built that endpoint refused every documented form of the call. An actor that promises you real publisher URLs is promising you something that breaks without warning, and a broken link is worse than an honest one.

So this row gives you what is solid: the Google News link, which always resolves in a browser, plus `publisherName` and `publisherHomeUrl` from Google's own data. If your pipeline needs the publisher's article URL, open `googleNewsUrl` — the redirect works for a reader. If that ever becomes cheap and reliable to do at scale, it arrives as a column, not as a surcharge.

### What it costs

Two charged events. Nothing is charged for starting a run, and nothing is charged for a row that did not land.

| event | what one unit is | Apify free plan | paid plans, from |
|---|---|---|---|
| **Article** | one article row, from a query, a topic section, a place or the top stories | $0.0032 | $0.0008 |
| **Query check** | one query, topic or place whose feed came back with articles in it — including a run where you already held every one of them, and the answer is "nothing new since your last run" | $0.002 | $0.002 |

**100 articles from one query** is 100 Articles plus 1 Query check: **$0.322** on the Apify free plan, **$0.082** from the cheapest paid tier.

**Ten articles** — the shape an agent asks for — is **$0.034** and **$0.010**. There is no fee to start a run, so a small ask is a small bill.

The **Query check** is what makes a schedule honest in both directions. Your account's memory means a query you already ran costs you nothing in Article rows the second time — as long as the run's API token can open key-value stores in your account — and the check is the flat, disclosed price of us going and looking. A query we could not fetch, one you set to a value we do not recognise, and one that matched nothing at all are never charged it.

### How often the data changes

| feed | how fast it moves |
|---|---|
| a search query with no time window | the top of it turns over through the day; the tail is stable for days |
| a search query with **Time window** set to `1h` or `1d` | a stream — run it as often as your window is wide and you will see new rows each time |
| a topic section or the top stories | rebuilt continuously; the leading stories change within the hour |
| an article's own `publishedAt` and `publisherName` | fixed the moment it is published, and never revised |

**A note on freshness, because it is the thing most often mis-sold.** Google News indexes a publisher on Google's schedule, not the publisher's. On measured feeds the newest article sat between four and fourteen hours behind the moment of the run. A one-hour window is a real filter, not a promise that the last hour of the world's news is already in the index.

**The schedule that stays cheap.** Set **Time window** to the gap between your runs and leave **Skip articles you already have** on. Every article this actor has already delivered to your account is skipped on the next run — no row and no charge — so a daily schedule pays for what is new and the one Query check, and nothing else. Switch the setting off to get them anyway, marked as repeats and still uncharged. The memory is a key-value store in your own Apify account, so a run started with a scoped API token in restricted-access mode needs key-value store Read, Write and Create permission, or Actor runs set to Full access (Write is what lets the run remember what it delivered; without it every run pays again); without it the run says so on its status line and on its first row, and cannot skip what you already have.

### Every run ends with a receipt

The last row of every run is a receipt: articles delivered by target, what was asked for, what your account already had, what your time window dropped, what stopped the run, and the charged totals for both events — so an invoice reconciles from the dataset itself. **A cost cap or a time limit ends the collecting, never the delivering** — rows already in hand are always written out.

### Related actors

- What the whole internet is searching for right now: `steadyfetch/google-trends-now-scraper`. A keyword's full interest curve: `steadyfetch/google-trends-scraper`.
- What is trending on the social platforms instead: `steadyfetch/social-trends-scraper`.
- The discussion under a story rather than the story: `steadyfetch/reddit-scraper`.

### Something not right?

Open the **Issues** tab on this actor with your run ID and the input you used, and it gets looked at. If it earned its keep, a rating helps other buyers find it, and saving the actor keeps it one click away.

# Actor input Schema

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

Search terms, one per line — "electric vehicles", "openai", or Google News search syntax like site:reuters.com ukraine. Each term is fetched once and returns up to about 100 article rows, newest first, under the language, country and time window set below. A term that matches nothing ships one uncharged row and is never retried, and no term is ever widened or rewritten to find something — you get what you typed or you get told. Leave this empty and the run returns a live sample instead of collecting anything, at no result fee.

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

Google News' own section front pages, one per line: WORLD, NATION, BUSINESS, TECHNOLOGY, ENTERTAINMENT, SPORTS, SCIENCE or HEALTH. Not case sensitive. Each section is a whole editorial page rather than a search, so it is the door to use for "what is the news in technology right now". A subject that is not one of those eight is a search term — put it in "Search queries" instead, and a value this actor does not know ships one uncharged row naming the eight that work rather than being swapped for one of them.

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

Hard ceiling for the WHOLE run, counting every article row across every query and every topic section. Exact, never overshot, and never padded: the ask is split evenly across your inputs, and a feed carrying fewer articles than its share gives you what it carries and says so on its own row. Accepted range 1 to 50,000; a number outside it is moved to the nearest value in range and one uncharged note row says so, rather than the run being refused.

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

How far back to look: 1h, 6h, 12h, 1d, 3d, 7d, 14d or 30d. Leave it empty for no window at all, which is Google's own default ordering. Set it to the gap between your scheduled runs and leave "Skip articles you already have" on, and a schedule pays for what is new and nothing else. Google indexes a publisher on its own schedule, so a short window is a real filter on publication time and not a promise about how fast the index moves.

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

The edition language, as a two-letter ISO 639-1 code — en, es, fr, de, pt, ar, hi, ja, it, nl and the rest. It decides which Google News edition answers, so it changes which publishers you get, not just the interface. A code this actor cannot read is refused on an uncharged row naming what works; it is never quietly swapped for English, because that would bill you for articles in a language you did not ask for.

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

The edition country, as a two-letter ISO 3166-1 code — US, GB, CA, AU, IN, DE, FR, SA, BR, JP and the rest. Pair it with the matching language for a national edition (for example de + DE). A code this actor cannot read is refused on an uncharged row naming what works, and is never swapped for another country.

## `skipSeenArticles` (type: `boolean`):

ON (default): an article already delivered to your account is skipped — no row, no charge — and the run says how many. OFF: those articles are delivered again anyway, marked repeat: true, and still not charged. Anything older than 90 days in your account's memory counts as new again either way. The flat Query check is charged either way when the feed came back carrying articles, because "nothing new since your last run" is the answer a schedule is paying for.

## Actor input object example

```json
{
  "queries": [],
  "topics": [],
  "maxItems": 100,
  "language": "en",
  "country": "US",
  "skipSeenArticles": true
}
```

# Actor output Schema

## `items` (type: `string`):

One row per article delivered, with the same columns whichever door it came through — a search query, a Google News topic section, a place, or the top stories: the query or section that produced it and which kind it was, the headline with the publisher suffix Google appends removed and again exactly as Google publishes it, the article's link on Google News, Google's own stable article id, the publication time as an ISO-8601 UTC timestamp and again exactly as Google wrote it, the publisher's name and their site's home address, how many other outlets Google grouped under the same story, and the language, country and time window the row was fetched under. ONE FLAG, ONE EVENT: `charged` is the row itself and `chargedEvents` names the event that paid for it — `Article`, and never two. A row marked `repeat: true` is one your account already had and asked to be given again: delivered, and not charged. THE LINK IS GOOGLE'S: `googleNewsUrl` is the article's Google News link, not the publisher's own URL. Google publishes every article behind an opaque redirect of its own, and this actor does not resolve it, does not promise it and never charges for one — what you get instead is the link that always opens plus `publisherName` and `publisherHomeUrl` from Google's own data.

## `targets` (type: `string`):

One row for every search query and every topic section the run reached, saying how many articles Google News is carrying for it, how many were delivered, how many your account already had, and whether the flat `Query check` event was charged for it. THIS IS THE ONLY ROW THAT EVER CARRIES A `Query check`: it is charged once per query or section whose feed came back carrying at least one article — including a run where you already held every one of them and the answer is "nothing new since your last run" — and it is never charged for a feed we could not fetch, a value we do not recognise, or a query that matched nothing at all. No article row ever bills it.

## `misses` (type: `string`):

One uncharged row for every query or section that returned less than it was asked for, saying which happened: `no_results` (Google served the feed and it carried no article at all — a definitive answer, never retried and never widened, and neither the article fee nor the Query check is charged), `source_not_found` (Google answered "not found" for that feed address — a section or place it does not publish), `feed_unavailable` (Google would not serve the feed on this run — ours, and a re-run is the fix), `parse_failed` (Google answered with a body this build could not read as a feed — also ours), `input_error` (a value this actor could not use, naming the field and never the value), `undeclared_field` (a setting this actor does not have, so it was not applied), and `skipped_max_items`, `skipped_budget` and `skipped_deadline` (your own row ceiling, your own maxTotalChargeUsd, or the run clock stopped it first). None of these is charged, and each row says in a sentence what happened and what to do about it.

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

The last row of every run: articles delivered from queries against topic sections, what was asked for, how many inputs were answered, how many articles your account already had, how many inputs had nothing new since your last run, what stopped the run, and the charged totals for both events — `Article` and `Query check` — so an invoice reconciles from the dataset itself.

# 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": [],
    "topics": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadyfetch/google-news-rss-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": [],
    "topics": [],
}

# Run the Actor and wait for it to finish
run = client.actor("steadyfetch/google-news-rss-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": [],
  "topics": []
}' |
apify call steadyfetch/google-news-rss-scraper --silent --output-dataset

```

## MCP server setup

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