# Google Search Scraper – Web & News SERP Results (`simple.actors/google-search`) Actor

Scrape Google search results as data: title, link, snippet and position for web search, or headline, publisher link, date and source from Google News. Uses Apify's Google SERP proxy for web and Google News's own feeds for news. No API key, no login, no browser. Unofficial.

- **URL**: https://apify.com/simple.actors/google-search.md
- **Developed by:** [Simple Actors](https://apify.com/simple.actors) (community)
- **Categories:** SEO tools, News, Business
- **Stats:** 2 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 web results page reads

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?

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 Search Scraper – Web & News SERP Results

Scrape Google search results as structured data. Type what you would type into
the search box — a business, a person, a topic, a `site:` query — and every
result comes back as a row: title, link, snippet and position, in Google's own
ranking order. Built for SERP tracking, media monitoring, lead research and SEO
work, with two search types off one input.

- **Web** (the default) — what google.com shows: the site itself, coverage,
  profiles, listings. Read from Google's real results pages through Apify's
  Google SERP proxy, the sanctioned route for exactly this.
- **News** — what Google News lists: headline, the publisher's own link,
  publish date and source, newest first, up to 100 stories a search. Much
  cheaper per result, and the right type for monitoring coverage.

**No API key, no login, no browser, no account of yours involved.** A search
finishes in a few seconds.

**Web: $3.50 per 1,000 result pages** (about ten results each — $0.0035 for
a typical search). **News: $0.30 per 1,000 searches plus $0.05 per 1,000
stories.** Apify platform usage included,
nothing else to pay. A search that cannot be read is never charged.
*Unofficial. Not affiliated with, endorsed by, or sponsored by Google.*

### Features

- **Two search types, one input** — google.com web results, or Google News
  stories.
- **Google's operators all work** — `"exact phrase"` in quotes,
  `site:example.com`, `-excluded` words.
- **Ranking position preserved** — `position` and `page` on every web result, in
  Google's own order.
- **Google News links unwrapped** — each story's `news.google.com/rss/articles/…`
  wrapper is resolved to the publisher's real address without a browser, and
  remembered between runs.
- **Every news story is dated** — a guaranteed `date` and `timestamp`, plus a
  stable `id` for deduplicating across scheduled runs.
- **Date filtering** — `onlyNewerThan` takes `24 hours`, `last 7 days` or an ISO
  date; on news it is also sent to Google as its `when:` operator.
- **Editions and languages** — pick the Google News edition by `language` and
  `country`, so a UK search ranks UK publishers.
- **Paste a Google URL directly** — a search-results URL, a News tab
  (`tbm=nws`), a Google News topic, section, publication or front page, or an
  RSS link.
- **Relaxed queries flagged, not hidden** — `queryRelaxed` is true when Google
  found no exact match and dropped the quotes.
- **Paging stops early** — a thin query never pays for empty pages.
- **Runs stay green.** A search that cannot be read becomes an error row, so one
  bad search never costs the rest of the job.

### Input

```json
{
  "queries": ["Cafe Charmant Bleecker Street"],  // one search per line
  "searchType": "web",        // "web" = google.com results, "news" = Google News stories
  "maxItems": 10,             // results per search — the cost knob on web (~10 per page)
  "onlyNewerThan": "7 days",  // optional: "24 hours", "last 7 days", "2026-08-01"
  "language": "en-US",        // Google News edition language
  "country": "US",            // Google News edition country, two-letter code
  "resolveLinks": true,       // news only: unwrap Google's link to the publisher's own
  "proxy": { "useApifyProxy": true }
}
```

That returns the results a person would see: the venue's own website, the
Eater story about its opening, its Instagram, its Yelp page — title, link and
snippet for each.

Google's operators all work:

```json
{
  "queries": [
    "\"Cafe Charmant\" reviews",
    "site:nasa.gov mars",
    "bradenton council -football"
  ]
}
```

| Field | Type | Default | What it does |
|---|---|---|---|
| `queries` | array | — | Search terms, one per line. Google's operators work. |
| `searchType` | string | `web` | `web` = google.com. `news` = Google News. |
| `startUrls` | array | — | Google pages to read instead of, or as well as, terms. A News-tab URL keeps its own tab regardless of `searchType`. |
| `maxItems` | integer | 10 web / 100 news | Results per search. Web pages come ~10 at a time and each page is a request. |
| `language` | string | `en-US` | Edition language: `en-US`, `en-GB`, `fr`, `de`, `es-419`, `hi`, `ja`… |
| `country` | string | `US` | Edition country: `US`, `GB`, `CA`, `AU`, `IN`, `DE`, `FR`… |
| `onlyNewerThan` | string | — | Keep only results newer than a window or ISO date. Exact on news, best-effort on web. |
| `resolveLinks` | boolean | `true` | News only. Resolve Google's wrapped link to the publisher's real address. |
| `proxy` | object | datacenter | News reads only. Web search always uses Apify's Google SERP proxy and is not configurable. |

#### How many results

Google serves about ten results a page and no longer honours a bigger page
size, so `maxItems` is the cost knob for web search: the default 10 is one
page ($0.0035), 25 is three, 100 is up to ten. Paging stops early the moment
Google repeats itself, so a thin query never pays for empty pages.

#### News search

```json
{
  "queries": ["bradenton city council"],
  "searchType": "news",
  "onlyNewerThan": "24 hours"
}
```

News search reads Google News's own feeds: up to 100 stories in one request,
each with a publish date and the publisher's real link (Google's wrapped
links are resolved without a browser, and remembered between runs). It also
reads Google News topic, section and publication pages and the front page of
any edition, pasted into `startUrls`. If you are polling for new coverage,
this is the type to use — it is a fraction of the price and every story is
dated.

#### Fresh results only

```json
{
  "queries": ["ai regulation"],
  "onlyNewerThan": "7 days"
}
```

The window takes a span like `"24 hours"`, `"last 7 days"` or an ISO date.
One honest difference between the types: on news the window is exact — every
story is dated, and the window is also sent to Google as its `when:`
operator, so the hundred places are spent inside it. On web it is
best-effort: only results whose snippet states a date can be judged, and the
undated majority is kept rather than silently dropped, with `date` null. If
the window matters, use the news type.

#### Editions and languages

```json
{
  "queries": ["council planning"],
  "language": "en-GB",
  "country": "GB"
}
```

`language` as Google writes it (`en-US`, `fr`, `es-419`…), `country` as a
two-letter code. Applies to both types.

### Output

One item per result, in the run's dataset. A web result:

```json
{
  "type": "result",
  "title": "Cafe Charmant | West Village NYC",
  "link": "https://www.cafecharmantnyc.com/",
  "domain": "cafecharmantnyc.com",
  "snippet": "340 Bleecker Street New York, NY 10014 (212) 308-3408",
  "displayedUrl": "https://www.cafecharmantnyc.com",
  "date": null,
  "timestamp": null,
  "query": "Cafe Charmant Bleecker Street",
  "searchUrl": "http://www.google.com/search?q=Cafe+Charmant+Bleecker+Street&hl=en-US&gl=US",
  "page": 1,
  "position": 3,
  "totalResults": 135,
  "queryRelaxed": false,
  "retrievedAt": "2026-08-24T05:04:18.210Z"
}
```

| Field | What it is |
|---|---|
| `title` | The result's title. |
| `link` | The site's own URL, exactly as Google links it. |
| `domain`, `displayedUrl` | The host, and the breadcrumb address Google displays. |
| `snippet` | The text under the title, including any date prefix Google printed. |
| `date`, `timestamp` | Only when Google printed a date in the snippet; null otherwise, never guessed. |
| `position`, `page` | The result's place in Google's ranking, 1 first, and the results page it came from. |
| `totalResults` | Google's own "About N results" estimate, when it printed one. |
| `queryRelaxed` | True when Google found no exact matches and searched without the quotes — the rows a person would see, flagged rather than passed off as exact matches. |

A news story instead carries `sourceName`, `sourceUrl`, a guaranteed `date`,
`googleNewsUrl` (Google's wrapped link), `linkResolved`, an `id` that is
stable across runs for deduplication, and `relatedStories` on front-page and
topic feeds. News stories are emitted newest first; web results in Google's
order.

A search that could not be read is its own row with `type: "error"`, an
`error` code and an `errorDescription`, so one bad search never costs the
rest of the job. The run itself stays green either way, and its status
message says how many searches could not be read — so if you poll on a
schedule, check for `type: "error"` rows rather than trusting the run status.

An empty dataset means the searches were read and Google lists nothing for
them. It never means the search could not be made; that arrives as an error
row instead.
A news story in full — every field `searchType: "news"` emits:

```json
{
  "type": "story",
  "title": "Council approves downtown redevelopment plan",
  "link": "https://www.bradenton.com/news/local/article123456.html",
  "linkResolved": true,
  "googleNewsUrl": "https://news.google.com/rss/articles/CBMiK2h0dHBzOi8vd3d3…",
  "id": "CBMiK2h0dHBzOi8vd3d3LmJyYWRlbnRvbi5jb20…",
  "date": "2026-08-24T11:32:00.000Z",
  "timestamp": 1787052720,
  "sourceName": "Bradenton Herald",
  "sourceUrl": "https://www.bradenton.com",
  "domain": "bradenton.com",
  "relatedStories": [{ "title": "…", "url": "…", "sourceName": "…" }],
  "query": "bradenton city council",
  "feedUrl": "https://news.google.com/rss/search?q=…",
  "position": 1,
  "retrievedAt": "2026-08-24T12:01:03.118Z"
}
```

### How to use

#### From Apify Console

1. Open the Actor and click **Try for free** / **Start**.
2. Put one search per line into **Search terms**. Google's operators work —
   `"exact phrase"`, `site:example.com`, `-excluded`.
3. Choose **Search type**: *Web* for what google.com shows, *News* for coverage
   monitoring.
4. Set **Results per search** — on web this is the cost knob, since results come
   about ten to a page. On news, up to 100 arrive in one request.
5. For a news edition, set **Language** and **Country** to the audience you care
   about, not the country the news is about.
6. Click **Start**, then open the **Dataset** tab and export as JSON, CSV or
   Excel.

#### From the API

```bash
curl -s "https://api.apify.com/v2/acts/simple.actors~google-search/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"queries": ["site:nasa.gov mars"], "maxItems": 20}'
```

News monitoring, with the JavaScript client:

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('simple.actors/google-search').call({
    queries: ['bradenton city council'],
    searchType: 'news',
    onlyNewerThan: '24 hours',
    country: 'US',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
// Deduplicate across scheduled runs on `id`, which is stable.
```

### Use cases

- **SERP rank tracking** — check where a domain sits for a set of keywords over
  time, using `position` and `page` on every web result.
- **Media and brand monitoring** — poll `searchType: "news"` with
  `onlyNewerThan` on a schedule and deduplicate on `id` to catch new coverage of
  a company, person or topic.
- **Lead research and prospecting** — resolve a business name to its own
  website, listings and profiles in one search, ready to feed into a contact
  scraper.
- **SEO competitor and content research** — run `site:` queries to see what
  Google has indexed for a competitor, and read the snippets it chose.
- **Local news aggregation** — read Google News topic, section and publication
  feeds for a region, with the publisher's real link rather than a Google
  wrapper.
- **Dataset seeding** — turn a list of search terms into a link corpus for
  further crawling.

### Usage notes

Simple, transparent pay-per-result pricing — no subscriptions.

#### Pricing

| Event | Price |
|---|---|
| Web results page read (~10 results) | $0.0035 |
| News search read | $0.0003 |
| News story returned | $0.00005 |

What that comes to:

- A web lookup at the default depth: **$0.0035** — $3.50 per 1,000 searches.
- A deep web search, 100 results: **up to $0.035**.
- A news search polled hourly that usually finds nothing new: **about $0.22
  a month**.
- A news search returning its full hundred stories: **about half a cent**.

### Limits worth knowing

- **Web results come ten a page.** Google retired the bigger page size;
  depth is paging, and paging is what costs.
- **News caps at 100 stories a search**, in one cheap request, with no next
  page.
- **The two types answer different questions.** Web is "what does Google
  show for this?"; news is "what coverage exists?". A place, a product or a
  person usually wants web; a monitored topic usually wants news.
- **Editions differ.** Set `language` and `country` to the audience you care
  about.

### FAQ

**Is scraping Google search results legal?**
Results come from Google and are subject to Google's terms — check the
platform's ToS before using them. Web search here goes through Apify's Google
SERP proxy, which is the sanctioned route to Google's results page, and news
search reads the RSS feeds Google News publishes openly.

**Do I need a Google API key or a SerpAPI account?**
No. There is no key, no login, no browser and no quota of your own to manage.

**Does it support pagination?**
Yes, on web search. Google serves about ten results per page and each page is
one request, so `maxItems` decides how many pages are read — 10 is one page, 100
is up to ten. Paging stops early the moment Google repeats itself. News search
does not page: up to 100 stories arrive in a single request and there is no next
page.

**Why is `date` null on my web results?**
Google only prints a date in some snippets. When it does not, the date is left
null rather than guessed. Every *news* story is dated, so use
`searchType: "news"` when the date matters.

**How do I get the publisher's real URL instead of a news.google.com link?**
That is the default. `resolveLinks` is on, so each story's wrapped link is
resolved to the publisher's own address and `linkResolved` is `true`. Turn it
off for a faster run and `link` stays the Google wrapper.

**How do I monitor a topic without getting the same stories every run?**
Poll with `searchType: "news"` and `onlyNewerThan` set shorter than the gap
between runs, then deduplicate on `id`, which is stable across runs.

**How do I know a search failed if the run stays green?**
Check for rows with `type: "error"` — that is the failure channel by design, so
one bad search never costs the rest of the job. The run's status message also
counts how many searches could not be read.

Results come from Google and are subject to Google's terms. Web search uses
Apify's Google SERP proxy; news search reads the feeds Google News publishes.
Unofficial, and not affiliated with Google.

# Actor input Schema

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

What to search Google for, one search per line. Google's operators work: "exact phrase" in quotes, site:example.com to limit to one site, a minus sign to exclude a word. Web search returns about 10 results per page requested (see "Results per search"); news search returns up to 100 stories.

## `searchType` (type: `string`):

What kind of Google search. "web" is google.com — title, link, snippet, in Google's ranking order. "news" is Google News — headline, the publisher's own link, date and source, newest first, and much cheaper per result. A pasted Google URL in "Google page links" keeps its own tab regardless of this setting.

## `startUrls` (type: `array`):

Google pages to read instead of, or as well as, search terms: a google.com search results URL (its News tab, tbm=nws, is read as a news search; anything else as a web search), a Google News search, topic, section or publication page, the Google News front page, or a Google News RSS link. Use "Search terms" above for plain queries.

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

How many results to return per search. Web search: Google serves about 10 per page and every page costs one search request, so the default of 10 is one page and 100 is up to ten — this is the cost knob. News search: up to 100 stories arrive in one request, so the default is all of them; lower it if you want fewer. Paging stops early when Google has no more.

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

Edition language as Google News writes it: en-US, en-GB, fr, de, es-419, hi, ja… Together with the country it picks which Google News edition answers — the same search returns different stories in different editions. Defaults to en-US.

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

Edition country as a two-letter code: US, GB, CA, AU, IN, DE, FR… Defaults to US. Pick the country the readers are in, not the country the news is about — a search for a UK council from the US edition still works, but the GB edition ranks local publishers higher.

## `onlyNewerThan` (type: `string`):

Keep only results newer than this point. Takes a window like "24 hours", "last 7 days" or "90 minutes", or an ISO date such as 2026-08-01. On a news search it is exact — every story is dated, and the window is also sent to Google as its when: operator. On a web search it is best-effort: only results whose snippet states a date can be judged, and the undated majority is kept rather than silently dropped.

## `resolveLinks` (type: `boolean`):

News search only; web results already carry the real address. Google News hands out its own wrapped links (news.google.com/rss/articles/…), which only a browser can follow. On, each story's link is resolved to the publisher's real address. Off, the run is faster and `link` is the Google wrapper. Resolved links are remembered between runs.

## `proxy` (type: `object`):

Used for news reads only — defaults to Apify's datacenter proxy, which is included in every plan and is enough for Google News. Web search always goes through Apify's Google SERP proxy, which is the sanctioned route to Google's results page and is not configurable here.

## Actor input object example

```json
{
  "queries": [
    "site:nasa.gov mars"
  ],
  "searchType": "web",
  "startUrls": [],
  "maxItems": 10,
  "language": "en-GB",
  "country": "GB",
  "onlyNewerThan": "24 hours",
  "resolveLinks": true,
  "proxy": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `stories` (type: `string`):

One row per result: title, link, snippet or source, date and the search it answered.

## `links` (type: `string`):

Resolved publisher links beside the Google News wrapped ones.

## `raw` (type: `string`):

Every field of every item, exactly as pushed.

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

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

# Run the Actor and wait for it to finish
run = client.actor("simple.actors/google-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": [
    "NASA"
  ],
  "startUrls": []
}' |
apify call simple.actors/google-search --silent --output-dataset

```

## MCP server setup

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