# Google Search Results Scraper: Organic & SERP Boxes (`vexaloom-labs/google-search-results-scraper-organic-and-serp`) Actor

Search Google and get organic results plus AI Overview, knowledge panel, People Also Ask, related searches, local pack, top stories and ads for each query, across 48 countries with language and date filters.

- **URL**: https://apify.com/vexaloom-labs/google-search-results-scraper-organic-and-serp.md
- **Developed by:** [vexaloom-labs](https://apify.com/vexaloom-labs) (community)
- **Categories:** SEO tools, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 Search Results Scraper: Web, News, Images & Videos

Run any search term through Google and get back structured results for the surface you need: classic web results with ads and SERP features, the News tab, the Images tab, or the Videos tab. Point it at a list of queries, choose a country and language, and it returns one structured record per query/page.

### What this actor does

- Searches web, news, images or videos with one `searchType` choice
- Web results: organic results, ads, People Also Ask, related searches, knowledge panel, local pack, top stories, sports tables and optional extra boxes
- Images: title, source, page URL, thumbnail, original image URL and dimensions
- News: headline, source, link, published time and snippet
- Videos: title, link, video ID, publisher/channel, duration and thumbnail
- Country/language targeting, time filters, custom date ranges, city-level `uule` hints and Google search operators
- Optional real destination URLs for web organic results, and an optional browser-rendered AI Overview
- No proxy setup or credentials required: the actor handles its own access

### Output per search result page

Each run produces one record per query (per page, if `maxPagesPerQuery` > 1). Fields that Google does not render for a query are omitted, not filled with placeholders.

**Web (`searchType: "web"`):**

- `searchQuery` — term, page, country, language, search type and results-per-page metadata
- `organicResults` — `{position, title, url, displayedUrl, destinationUrl, snippet, siteLinks}`. `url` is the working Google result link; set `includeDestinationUrl` to add the real destination.
- `paidResults` — ad slots, when Google renders any
- `peopleAlsoAsk` — related questions
- `relatedQueries` — suggested searches
- `knowledgePanel` — entity panel for people, places and organizations
- `localPack` — local business results with rating, review count and address
- `topStories` — news carousel results
- `sportsTable` — standings when Google renders a real table (best-effort; current grid layouts may not populate it)
- `aiOverview` — only when `includeAiOverview` is enabled and Google renders one
- `resultsTotal` — Google's own rough estimate, which fluctuates between pages and renders; treat it as volatile, not a stable volume metric
- `hasNextPage` — whether another page is available
- `weatherBox`, `stockBox`, `timeZoneBox`, `currencyConverterBox`, `unitConverterBox`, `jobsPack`, `videoPack`, `shoppingPack`, `dictionaryBox` — opt-in via `includeExtraBoxes`

**News (`searchType: "news"`):** `newsResults[]` with `position`, `title`, `url`, `source`, `publishedAt` (ISO 8601 when Google exposes a timestamp), `publishedTimeText` and `snippet`.

**Images (`searchType: "images"`):** `imageResults[]` with `position`, `title`, `source`, `pageUrl`, `thumbnailUrl`, `originalImageUrl`, `width` and `height`. Original URLs come from the publisher as Google reports them; some hosts block hotlinks or let URLs expire, so validate before fetching. The thumbnail is returned independently.

**Videos (`searchType: "videos"`):** `videoResults[]` with `position`, `title`, `url`, `videoId`, `publisher`, `channel`, `duration` and `thumbnailUrl`.

**Error rows:** a query that fails outright, or is blocked on every attempt, produces `{"type": "error", "query": ..., "reason": ...}` instead of page records.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `queries` | array | – | Search terms; each is searched separately. |
| `searchType` | string | `web` | `web`, `news`, `images` or `videos`. |
| `maxResults` | integer | `100` | Maximum items per query (1–200). Web results stop at Google's own ~70–100 ceiling; images return 50–100; news/videos paginate in 10-result steps (news pages may render 10–22 cards). |
| `countryCode` | string | *(empty = US)* | Country for the Google domain and searcher-location signal. |
| `restrictResultsCountry` | string | *(empty = any)* | Only return pages targeting this country (Google's `cr`). |
| `languageCode` | string | *(empty)* | Google interface language (e.g. `en`, `de`). |
| `restrictResultsLanguage` | string | *(empty)* | Only return pages written in this language (e.g. `en` or `en,fr`). |
| `maxPagesPerQuery` | integer | `1` | Pages to crawl per query for web/news/videos (1–10). Images are one page. |
| `timePeriod` | string | *(empty = any)* | `hour`, `day`, `week`, `month` or `year`. |
| `safeSearch` | string | *(empty = default)* | `active` or `off`. |
| `includeAiOverview` | boolean | `false` | Opt-in browser-rendered AI Overview for web. Slower; not guaranteed. |
| `includeDestinationUrl` | boolean | `false` | Resolve web organic links to their real destination. Adds one lookup per result. |
| `csvFriendlyOutput` | boolean | `false` | Web only: one organic/paid result per row. |
| `includeExtraBoxes` | boolean | `false` | Web only: weather, time zone, converter, stock, jobs, videos, shopping, dictionary boxes. |
| `uule` | string | *(empty)* | Google-encoded location for city-level targeting; best-effort. |
| `dateFrom` / `dateTo` | string | *(empty)* | Custom date range (`YYYY-MM-DD`), set together. Overrides `timePeriod`. |
| `exactPhrase` | boolean | `false` | Wrap each query in quotes. |
| `site` | string | *(empty)* | `site:` operator; results are checked against the domain and off-domain ones are dropped. |
| `intitle` / `intext` / `inurl` / `fileType` | string | *(empty)* | Search operators sent to Google as-is. |
| `excludeTerms` | string | *(empty)* | Words to exclude, comma- or space-separated. |

#### Examples

Web rank check with a time filter:

```json
{
  "queries": ["best running shoes 2026"],
  "searchType": "web",
  "countryCode": "us",
  "maxResults": 30,
  "maxPagesPerQuery": 4,
  "timePeriod": "month",
  "includeDestinationUrl": true
}
```

News monitoring:

```json
{
  "queries": ["tesla"],
  "searchType": "news",
  "countryCode": "us",
  "maxResults": 20,
  "maxPagesPerQuery": 2
}
```

Image research:

```json
{
  "queries": ["tesla cybertruck"],
  "searchType": "images",
  "countryCode": "us",
  "maxResults": 50
}
```

### Use cases

- **SEO monitoring** — track web ranking positions across countries and languages
- **News monitoring** — collect headlines, sources and publication times
- **Visual research** — gather image thumbnails, sources and dimensions
- **Video research** — collect video titles, channels and durations
- **SERP feature tracking** — monitor ads, PAA, knowledge panels, local packs and AI Overviews
- **Content research** — mine related searches and questions

### FAQ

**Is this an official Google product?**
No. This is an independent actor that reads publicly available Google result pages. It is not affiliated with, endorsed by, or sponsored by Google.

**Do I need a proxy or Google account?**
No. The actor handles its own access and needs no cookies, logins, API keys or proxy configuration.

**How many results can I get per query?**
Web results stop at Google's own ceiling of roughly 70–100, even if you ask for 200. Images return 50–100 per query. News and videos paginate in 10-result steps and stop when Google stops returning results; a news page may render 10–22 cards.

**Why is `resultsTotal` sometimes a small number?**
It is Google's own estimate on that specific render. It fluctuates between pages and query types, so use it as a rough signal rather than a stable search-volume metric.

**Why are `paidResults`, `knowledgePanel`, `localPack` or `topStories` often empty?**
Google only renders those features for some queries. Ads are sparse even on commercial terms; local packs need local intent; knowledge panels need an entity. Their absence is normal, not an extraction failure.

**Why is `aiOverview` empty?**
AI Overview is opt-in because it requires a slower browser-rendered fetch, and Google still may not show one for a given query. The text is best-effort and headings/bullets may be flattened.

**What is `destinationUrl`?**
Google usually wraps organic links in a redirect. With `includeDestinationUrl` enabled, the actor follows that redirect and adds the real destination. If the lookup fails, `destinationUrl` is omitted and the working Google link remains in `url`.

**Why did `site:` return fewer results than expected?**
Google silently widens `site:` searches once the restricted corpus runs out. The actor checks each result against your domain and drops ones that do not belong, so a smaller but accurate set is expected. Social cards with follower counts are recognized as on-domain.

**Does CSV mode include news, images or videos?**
No. `csvFriendlyOutput` is a web-only reshape. Use the default JSON layout for the other search types.

**Are image URLs permanent?**
Thumbnail URLs are served by Google and are reliable. Original image URLs come from the publisher and may expire or be hotlink-protected; the actor returns the URL Google provides and does not runtime-validate every original, so a few may return 403/404.

# Actor input Schema

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

Google search queries. Each is searched separately; blank entries are dropped with a warning.

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

Which Google surface to scrape: web organic results, news cards, images, or videos.

## `maxResults` (type: `integer`):

Maximum items to return per query. Web results stop at Google's own ceiling of roughly 70-100; images return 50-100 per query and news/videos paginate in pages of 10.

## `countryCode` (type: `string`):

Country for the Google domain and searcher-location (gl) signal. Leave empty for US (google.com); if Precise Location is set and this is empty, the country is derived from it.

## `restrictResultsCountry` (type: `string`):

Only return pages whose content originates from this country (Google's cr parameter), independent of Country/gl. Leave empty for no restriction.

## `languageCode` (type: `string`):

Language of Google's own interface, e.g. en, de, fr, es. This does not restrict the language of the matched pages.

## `restrictResultsLanguage` (type: `string`):

Only return pages written in this language, e.g. en or en,fr for either. Leave empty for no restriction.

## `maxPagesPerQuery` (type: `integer`):

Result pages to crawl per query for web, news and videos. Images are a single page. Web results stop at Google's own ceiling of roughly 7-10 pages.

## `timePeriod` (type: `string`):

Filter results by relative time. Leave empty for any time.

## `safeSearch` (type: `string`):

Filter explicit content (safe=). Leave empty for Google's default.

## `includeAiOverview` (type: `boolean`):

Opt-in browser-rendered AI Overview for web searches. Slower and not guaranteed: Google may not show one, and the text is best-effort. Only applies to web search.

## `includeDestinationUrl` (type: `boolean`):

Add a destinationUrl field with the real destination behind Google's redirect link. Adds one lookup per organic result. Only applies to web search.

## `csvFriendlyOutput` (type: `boolean`):

For web search, output one organic/paid result per row instead of one SERP page per row. Other SERP features are not included in this layout.

## `includeExtraBoxes` (type: `boolean`):

For web search, also extract weather, time zone, currency/unit converter, stock, jobs, videos, shopping and dictionary boxes when present.

## `uule` (type: `string`):

Optional Google-encoded location for city-level targeting. Best-effort: country targeting is reliable, city precision is not guaranteed. Leave empty to use Country only.

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

Only include results published on or after this date (YYYY-MM-DD). Must be used with Date to.

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

Only include results published on or before this date (YYYY-MM-DD). Must be used with Date from.

## `exactPhrase` (type: `boolean`):

Wrap each query in quotes so Google matches it as an exact phrase.

## `site` (type: `string`):

Restrict results to this domain, e.g. nike.com. Every organic result is checked against it; off-domain results Google slips in are dropped.

## `intitle` (type: `string`):

Restrict results to pages containing this word in the title. Sent to Google as-is.

## `intext` (type: `string`):

Restrict results to pages containing this word in the body text. Sent to Google as-is.

## `inurl` (type: `string`):

Restrict results to pages containing this word in the URL. Sent to Google as-is.

## `fileType` (type: `string`):

Restrict results to a file type, e.g. pdf, doc, xls. Sent to Google as-is.

## `excludeTerms` (type: `string`):

Words to exclude, comma- or space-separated, e.g. jaguar, cats.

## Actor input object example

```json
{
  "queries": [
    "Hotels in NYC"
  ],
  "searchType": "web",
  "maxResults": 3,
  "countryCode": "us",
  "restrictResultsCountry": "",
  "languageCode": "en",
  "restrictResultsLanguage": "",
  "maxPagesPerQuery": 1,
  "timePeriod": "",
  "safeSearch": "",
  "includeAiOverview": false,
  "includeDestinationUrl": false,
  "csvFriendlyOutput": false,
  "includeExtraBoxes": false,
  "exactPhrase": false
}
```

# Actor output Schema

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

Dataset with scraped SERP data

# 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": [
        "Hotels in NYC"
    ],
    "searchType": "web",
    "maxResults": 3,
    "countryCode": "us",
    "restrictResultsCountry": "",
    "languageCode": "en",
    "restrictResultsLanguage": "",
    "maxPagesPerQuery": 1,
    "timePeriod": "",
    "safeSearch": "",
    "includeAiOverview": false,
    "includeDestinationUrl": false,
    "csvFriendlyOutput": false,
    "includeExtraBoxes": false,
    "uule": "",
    "dateFrom": "",
    "dateTo": "",
    "exactPhrase": false,
    "site": "",
    "intitle": "",
    "intext": "",
    "inurl": "",
    "fileType": "",
    "excludeTerms": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("vexaloom-labs/google-search-results-scraper-organic-and-serp").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": ["Hotels in NYC"],
    "searchType": "web",
    "maxResults": 3,
    "countryCode": "us",
    "restrictResultsCountry": "",
    "languageCode": "en",
    "restrictResultsLanguage": "",
    "maxPagesPerQuery": 1,
    "timePeriod": "",
    "safeSearch": "",
    "includeAiOverview": False,
    "includeDestinationUrl": False,
    "csvFriendlyOutput": False,
    "includeExtraBoxes": False,
    "uule": "",
    "dateFrom": "",
    "dateTo": "",
    "exactPhrase": False,
    "site": "",
    "intitle": "",
    "intext": "",
    "inurl": "",
    "fileType": "",
    "excludeTerms": "",
}

# Run the Actor and wait for it to finish
run = client.actor("vexaloom-labs/google-search-results-scraper-organic-and-serp").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": [
    "Hotels in NYC"
  ],
  "searchType": "web",
  "maxResults": 3,
  "countryCode": "us",
  "restrictResultsCountry": "",
  "languageCode": "en",
  "restrictResultsLanguage": "",
  "maxPagesPerQuery": 1,
  "timePeriod": "",
  "safeSearch": "",
  "includeAiOverview": false,
  "includeDestinationUrl": false,
  "csvFriendlyOutput": false,
  "includeExtraBoxes": false,
  "uule": "",
  "dateFrom": "",
  "dateTo": "",
  "exactPhrase": false,
  "site": "",
  "intitle": "",
  "intext": "",
  "inurl": "",
  "fileType": "",
  "excludeTerms": ""
}' |
apify call vexaloom-labs/google-search-results-scraper-organic-and-serp --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vexaloom-labs/google-search-results-scraper-organic-and-serp"
        }
    }
}
```

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/PlIxbe9L7Qn7c76R7/builds/NG6Y2OAdaEEnxj85d/openapi.json
