# Google News Scraper with Real Article URLs (`omraydev/google-news-search`) Actor

Scrape Google News articles by keyword, topic or website. Each result has the publisher's real article URL, title, source, publish date and snippet. Pick language, country and date range, and run many searches at once.

- **URL**: https://apify.com/omraydev/google-news-search.md
- **Developed by:** [Om Ray](https://apify.com/omraydev) (community)
- **Categories:** Agents, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.00 / 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.

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 with Real Article URLs

This actor searches Google News and gives you one row per article. You can search by keyword, pull a Google News topic such as TECHNOLOGY, or list the newest articles from a site like reuters.com. Many searches can go in one run.

Google News links point to news.google.com, not to the article. The actor decodes each one into the publisher's real URL, so `url` opens the actual story. If Google won't decode a link, the row keeps the Google link in `googleUrl`, sets `url` to null and `urlResolved` to false, and you aren't charged for it.

It reads Google's public RSS feeds over plain HTTP, with no browser, login or proxy. A run of 20 articles takes a few seconds, and 100 articles take about 10 seconds.

### Input

```json
{
  "queries": ["artificial intelligence"],
  "timeRange": "7d",
  "edition": "US:en",
  "maxItems": 20
}
```

- `queries`: keywords, one per line. Google's search operators work, for example `"electric vehicles" intitle:battery` or `ai site:reuters.com`.
- `topics`: Google News sections. Use `TOP_STORIES`, `WORLD`, `NATION`, `BUSINESS`, `TECHNOLOGY`, `ENTERTAINMENT`, `SPORTS`, `SCIENCE` or `HEALTH`, or paste a `news.google.com/topics/...` link.
- `sites`: domains such as `bbc.co.uk`. Each one runs as a `site:` search.
- `timeRange`: past hour, 24 hours, 7 days, 30 days, year, or any time.
- `startDate` and `endDate`: a fixed date range in UTC. These replace `timeRange`.
- `edition`: the language and country, such as `US:en`, `GB:en`, `DE:de` or `BR:pt-419`. The list only has editions that Google accepts, so you can't pick a combination that returns nothing.
- `maxItems`: the most articles to return for each query, topic or site.
- `dedupe`: on by default. An article that an earlier query already returned (same publisher URL) is skipped.
- `splitDateRange`: on by default. See the next section.
- `maxRunSeconds`: a hard time limit. The run keeps what it has collected when it hits it, and adds a free `incomplete` row for each query it didn't finish.

If a query has its own `when:`, `after:` or `before:` operator, the actor sends it as written and doesn't add or apply the date settings.

### About the 100-article limit

One Google News feed returns about 100 articles, and topic feeds about 30 to 70. To get more for a search, set `maxItems` above 100 and keep `splitDateRange` on. The actor then searches smaller date windows, newest first, until it reaches your limit or runs out of windows. This needs a time range or a start date. With "any time" you get one feed. When you set `startDate` or `endDate`, the actor also splits the range whenever the first feed comes back full, whatever `maxItems` is.

The smallest window is one day, and Google caps that at about 100 articles too. A very busy keyword can have more than that in a day, and the rest won't show up. For a busy keyword over 7 days, a run with `maxItems` of 300 came back with 300 distinct articles in 20 to 40 seconds.

Google treats `after:` and `before:` as whole days in US Pacific time, for every edition. The actor starts each search a day early and then drops anything published outside your range, so the dates you get match the UTC dates you asked for.

### Output

Here is a real row from the example input above:

```json
{
  "status": "ok",
  "message": null,
  "title": "Trump Says He Will Ban Term ‘Artificial Intelligence’ In Latest Push For ‘Super Intelligence’",
  "url": "https://www.forbes.com/sites/fionariley/2026/10/27/trump-vows-to-ban-term-artificial-intelligence/",
  "urlResolved": true,
  "googleUrl": "https://news.google.com/rss/articles/CBMinwFBVV95cUxNa3BBOFRzNmhiVi10YzJyUVAwWXdVUlRzOHg3bi0yZENqUWk0VzFxUFFMV2NFWUxtdEhyb1pNaTdLcU9RbWU0TDVBUXBHdnN5emZ4SzdVck8zUE5mbnNwbkdqV2VzTHY1cHdBWjlWUmppbDZyMWk0T3FLOUNKR0hwQmIyWlJ5ZlRFbUM4dFJrVGRnb1d4T2tqNUNXUjZUZzQ?oc=5",
  "source": "Forbes",
  "sourceUrl": "https://www.forbes.com",
  "publishedAt": "2026-10-27T17:38:12.000Z",
  "description": "Trump Says He Will Ban Term ‘Artificial Intelligence’ In Latest Push For ‘Super Intelligence’ - Forbes",
  "relatedArticles": [],
  "query": "artificial intelligence",
  "queryType": "search",
  "language": "en-US",
  "country": "US",
  "edition": "US:en",
  "feedUrl": "https://news.google.com/rss/search?q=artificial%20intelligence%20when%3A7d&hl=en-US&gl=US&ceid=US%3Aen",
  "scrapedAt": "2026-11-01T16:01:07.758Z"
}
```

Every row has the same fields:

| Field | What it holds |
| --- | --- |
| `status` | `ok` for an article. `no-results`, `error` or `incomplete` for a free row that explains why a query found nothing or stopped early. |
| `message` | The explanation on a status row. Null on article rows. |
| `title` | The headline, without the " - Source" that Google adds to the end. |
| `url` | The publisher's real article URL, or null if it couldn't be decoded. |
| `urlResolved` | True when `url` holds the decoded publisher URL. |
| `googleUrl` | The news.google.com link from the feed. |
| `source` | The publisher's name. |
| `sourceUrl` | The publisher's home page. |
| `publishedAt` | Publish time in ISO 8601, UTC. |
| `description` | The feed's snippet as clean text. Google puts the headline and publisher here, not an excerpt of the article. |
| `relatedArticles` | In topic feeds, other coverage of the same story, each with `title`, `source` and `googleUrl`. Empty for searches. |
| `query` | The query, `site:` search or topic that returned the article. |
| `queryType` | `search`, `site` or `topic`. |
| `language` | Google's `hl` value for the edition. |
| `country` | Google's `gl` value. |
| `edition` | Google's `ceid` value. |
| `feedUrl` | The RSS feed the article came from. |
| `scrapedAt` | When the row was written. |

The run summary, with counts per query and the reason the run stopped, is saved in the key-value store as `OUTPUT`.

### When nothing is found

If a query returns no articles, you get one free row with `status` set to `no-results` and a `message` that says why. For example, Google had no articles for that search in the time range, every article was outside your dates, or all of them were already returned by an earlier query. A topic name Google doesn't know, or a feed that fails to load, gives a free `error` row. The run still finishes successfully.

A query that stops early gets a free `incomplete` row. That happens when the run hits `maxRunSeconds`, when your spending limit is reached, or when some of the day windows in a split search fail to load. Queries the run never reached also get an `incomplete` row.

### Price

You pay $0.005 for each article that has a decoded publisher URL. That's $5 per 1,000 articles, with no charge for starting a run. Rows with `urlResolved: false` and status rows are free. The run stops when it reaches the spending limit you set.

### Limits

- Results are whatever Google News puts in its feeds. Search feeds hold about 100 articles and topic feeds fewer, and the ranking is Google's.
- The URL decoding uses the same call that the Google News website uses. In testing, 309 of 309 links decoded and every URL matched the publisher's domain. If Google changes that call, links can come back unresolved until the actor is updated. You won't be charged for those.
- Decoding fetches one small Google page per article, a few at a time with retries when Google asks it to slow down. That's why 100 articles take seconds rather than being instant.
- Google's feeds carry Google's own terms. Check that your use fits them.

If something breaks or looks wrong, open an issue on the Issues tab and it gets fixed fast, and if this actor helped you, an honest review on the Store helps other people find it.

# Actor input Schema

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

Keywords to search in Google News, one per line. Google search operators work, for example "tesla" intitle:recall, or ai site:reuters.com. If a query has its own when:, after: or before: operator, the date settings below are not added to it.

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

Google News sections: TOP_STORIES, WORLD, NATION, BUSINESS, TECHNOLOGY, ENTERTAINMENT, SPORTS, SCIENCE or HEALTH. You can also paste a news.google.com/topics/... link or its topic ID. Topic feeds hold about 30 to 70 stories.

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

Domains to pull recent articles from, such as reuters.com or bbc.co.uk. Each one runs as a site: search.

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

How far back to look. Ignored when you set a start or end date.

## `startDate` (type: `string`):

Only articles published on or after this day (UTC). Overrides the time range.

## `endDate` (type: `string`):

Only articles published on or before this day (UTC). Overrides the time range.

## `edition` (type: `string`):

The Google News edition to search. It sets the hl, gl and ceid parameters together, so the combination is always one Google accepts.

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

Upper limit of articles for each query, topic or site. One Google News feed holds about 100 articles, so above 100 the actor splits the date range into smaller windows (see the option below).

## `splitDateRange` (type: `boolean`):

When max articles is above 100, or a start or end date is set and the first feed comes back full, search smaller date windows one after another, newest first, until the limit is reached. Needs a time range or a start date. Does not apply to topics.

## `dedupe` (type: `boolean`):

Skip an article if an earlier query in the same run already returned the same publisher URL.

## `maxRunSeconds` (type: `integer`):

The run stops collecting after this many seconds and keeps what it has.

## Actor input object example

```json
{
  "queries": [
    "artificial intelligence"
  ],
  "topics": [],
  "sites": [],
  "timeRange": "7d",
  "edition": "US:en",
  "maxItems": 20,
  "splitDateRange": true,
  "dedupe": true,
  "maxRunSeconds": 300
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `summary` (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": [
        "artificial intelligence"
    ],
    "timeRange": "7d",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("omraydev/google-news-search").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"],
    "timeRange": "7d",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("omraydev/google-news-search").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"
  ],
  "timeRange": "7d",
  "maxItems": 20
}' |
apify call omraydev/google-news-search --silent --output-dataset

```

## MCP server setup

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

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/iYSJBAuPijlzHYclB/builds/7tsi3yTjy4qqfv4ya/openapi.json
