# Google SERP Scraper API – Search Results Scraper (`datascraperes/google-serp-scraper`) Actor

Scrape Google organic search results by query, country, language, and page range. Get clean SERP data including position, title, URL, and description, with pay-per-result pricing and no browser required.

- **URL**: https://apify.com/datascraperes/google-serp-scraper.md
- **Developed by:** [DataScraperES](https://apify.com/datascraperes) (community)
- **Categories:** SEO tools, Lead generation, AI
- **Features:** Limited permissions
- **Stats:** 17 total users, 5 monthly users, 98.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.45 / 1,000 serp results

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?

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

Extract structured Google organic search results for one or thousands of queries, or check where one domain ranks for each query. **Get clean, localized organic data for English-first SEO workflows** with predictable pay-per-event pricing.

### What this Actor does

Google Search SERP Scraper collects organic results from Google search interfaces, including Programmable Search, without requiring you to manage a browser or manually copy search pages. These results and domain positions can differ from an interactive Google.com search; this is not an exact reproduction of that page. In normal mode, every result includes the original query, Google page number, organic position, title, destination URL, and visible description. When `targetDomain` is set, the Actor switches to a focused domain-rank check and returns one ranking record per query.

You can search several markets and languages, request pages 1–10, export the Dataset, schedule recurring runs, or connect the results to another workflow through Apify.

### Use cases

- Monitor a domain's organic position for selected keywords and markets.
- Compare competitor domains by running the same rank Task with a different target.
- Research topics, content opportunities, and destination domains.
- Build recurring SERP datasets for reporting and change analysis.
- Collect source URLs for enrichment or lead-research workflows.

### How to use

1. Open the Actor in Apify Console.
2. Enter one or more search queries.
3. Leave `Target Domain` empty to collect all organic results, or enter a hostname/HTTP(S) URL to check its position.
4. Choose the first and last Google page, language, and country.
5. Click **Start**.
6. Open the **Dataset** to review or export the results.

The default input searches page 1 using English language and the United States as the target market. Use separate runs or Tasks for the United Kingdom, Canada, Australia, or other markets.

### Input

| Field | Type | Required | Default | Description |
|---|---|---:|---|---|
| `queries` | `string[]` | Yes | — | Search queries. Empty values are ignored and identical trimmed queries are collected once. Maximum: 10,000 entries. |
| `targetDomain` | `string` | No | empty | Optional hostname or HTTP(S) URL. When set, activates domain-rank mode and returns one record per query. `www.` and URL paths are normalized away. |
| `startPage` | `integer` | No | `1` | First Google results page, from 1 to 10. |
| `endPage` | `integer` | No | `1` | Last Google results page, from `startPage` to 10. |
| `language` | `string` | No | `en` | Two-letter language selected from the input form. |
| `country` | `string` | No | `us` | Two-letter target country selected from the input form. |

The total number of query/page combinations cannot exceed 10,000. For example, 5,000 queries across pages 1–2 produce 10,000 requested Google pages. This is the exact input used for the normal-mode output item below:

```json
{
  "queries": [
    "Apify web scraping"
  ],
  "targetDomain": "",
  "startPage": 1,
  "endPage": 1,
  "language": "en",
  "country": "us"
}
```

### Output

In normal mode, each organic result is stored as a separate Dataset item. The Dataset schema presents the fields in a table and keeps them available for export or API retrieval. This is the complete Dataset item from a real successful normal-mode run:

```json
{
  "query": "Apify web scraping",
  "page": 1,
  "position": 1,
  "title": "Apify: The largest marketplace of trusted tools for AI",
  "url": "https://apify.com/",
  "description": "67,073 tools for your AI ... Apify is the largest marketplace of trusted tools for AI. Get real-time web data, track competitors, generate leads, monitor social ..."
}
```

The default Key-Value Store also contains a `SUMMARY` record with the run status, requested, successful, failed, and remaining pages, result count, selected market, and spending-limit state.

When `targetDomain` is set, the Dataset contains one `domain_rank` record per query. It includes `targetDomain`, `status` (`found` or `not_found`), `found`, `position`, the matching or last checked `page`, `pagesScanned`, and the matching organic URL and metadata when available. The Actor stops scanning a query after the first matching domain. A `not_found` result is written only after every requested page for that query returned a complete SERP; failed or partial pages are retried and reported as incomplete instead of being treated as proof of absence.

The exact input for this domain-rank example is:

```json
{
  "queries": [
    "Apify web scraping"
  ],
  "targetDomain": "apify.com",
  "startPage": 1,
  "endPage": 1,
  "language": "en",
  "country": "us"
}
```

This is the complete Dataset item from a real successful domain-rank run using `targetDomain`:

```json
{
  "recordType": "domain_rank",
  "query": "Apify web scraping",
  "targetDomain": "apify.com",
  "status": "found",
  "found": true,
  "page": 1,
  "pagesScanned": 1,
  "position": 1,
  "title": "Web Scraper - Apify",
  "url": "https://apify.com/apify/web-scraper",
  "description": "Web Scraper ... Crawls arbitrary websites using a web browser and extracts structured data from web pages using a provided JavaScript function. The Actor supports ..."
}
```

### Pricing

This Actor uses pay-per-event pricing. Both modes use the existing `serp-result` event. In normal mode, one event is charged for each organic Google result successfully saved to the Dataset. In domain-rank mode, one event is charged for each completed query result (`found` or `not_found`). The rank record is an extra output projection of the same SERP delivery and does not create an additional charge event. Apify resolves the unit price from the user's Store plan:

| Apify plan | Price per result | Price per 1,000 results |
|---|---:|---:|
| Free | `$0.0006` | `$0.60` |
| Bronze | `$0.00055` | `$0.55` |
| Silver | `$0.0005` | `$0.50` |
| Gold | `$0.00045` | `$0.45` |
| Platinum | `$0.00045` | `$0.45` |
| Diamond | `$0.00045` | `$0.45` |

Only results successfully delivered to the Dataset are charged. This includes rows retained from a partial collection. Pages that produce no delivered rows, skipped pages after a rank is found, and the run summary do not create result charges. The Actor checks the run spending limit before delivering each billable result or rank record and stops when it cannot deliver another paid item within that limit. Apify's separate **API** tab provides current API and integration instructions.

For recurring rank monitoring, create a Task with `targetDomain`, keep the same query, country, language, and page range between runs, and schedule it daily or weekly so the resulting Datasets are easier to compare.

### Related Actors

Explore other public search and SEO Actors for alternative engines or complementary keyword research:

| Actor | Best for |
|---|---|
| [Bing Search Scraper – SERP Results](https://apify.com/datascraperes/bing-search-scraper) | Comparing organic visibility and ranked results on Bing. |
| [Yahoo Search Results Scraper](https://apify.com/datascraperes/yahoo-search-scraper) | Collecting localized Yahoo organic results for the same keyword sets. |
| [DuckDuckGo Search Scraper — Organic SERP API](https://apify.com/datascraperes/duckduckgo-search-results-scraper) | Researching privacy-focused search results across supported regions. |
| [Keyword Research & SERP Data](https://apify.com/datascraperes/keyword-research-serp) | Discovering keyword opportunities before collecting Google SERPs. |

### Limits and data quality

- A run accepts up to 10,000 queries and pages 1–10.
- A run can request at most 10,000 query/page combinations.
- Each Google page can deliver up to 10 organic results, for a maximum possible paid output of 100,000 results per run.
- Domain-rank mode returns at most one record per query and stops after the first matching organic result; `endPage` controls the maximum position checked.
- Country and language settings influence localization but do not strictly filter every result by country.
- Ads, shopping units, local packs, maps, and knowledge panels are not included.
- Google can return fewer results on deeper pages or when it has exhausted the available result set.
- Titles, snippets, URLs, and positions can change between runs as Google updates its results.
- Some organic results may not include a description.

The Actor retries temporary failures and performs a recovery pass for pages that initially fail. If pages remain unavailable or incomplete, it preserves delivered rows and reports `SUMMARY.complete=false` with a partial status. An exhausted source request does not by itself fail the run. A completed platform run is not proof of full collection: inspect the summary before using results as a complete snapshot. Progress is persisted so interrupted or migrated runs can continue without intentionally republishing completed results.

### Frequently asked questions

#### How do I activate domain-rank mode?

Enter a hostname or HTTP(S) URL in `targetDomain`. Leave it empty to keep the normal all-organic-results behavior. The Actor normalizes `www.` and matches the root domain and its subdomains without substring false positives.

#### Does the Actor return paid advertisements?

No. The Dataset contains organic Google results only.

#### Can I search several countries in one run?

A run uses one country and one language for all queries. Start separate runs when you need to compare different markets.

#### What does `not_found` mean?

It means the target domain did not appear in the requested organic pages and every page needed for that conclusion was complete. If Google returns a partial page or the page cannot be recovered, the query remains incomplete rather than receiving a false `not_found` result.

#### Why did I receive fewer than 10 results for a page?

Google may expose fewer organic results on a page, particularly on deeper pages or for narrow queries. Only results actually delivered to the Dataset are charged.

#### Can I request more than page 10?

No. `startPage` and `endPage` are limited to pages 1–10.

#### How do I control the maximum cost?

Set a maximum total charge for the run in Apify. The Actor checks available paid capacity before processing each page and stops when the spending limit is reached.

### Responsible use

Use the Actor only for lawful purposes. You are responsible for complying with applicable laws, regulations, privacy requirements, and website terms when collecting, storing, or using search-result data.

### Support

If a run produces unexpected results, open an issue in the Actor's **Issues** tab. Include the run ID, a reproducible query, page range, target domain when used, country, and language, but do not post credentials or sensitive information.

[Google Search SERP Scraper web guide, API examples and sample Dataset](https://github.com/datacrawler-edu/google-search-scraper-python)

# Actor input Schema

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

One or more search queries to scrape from Google. Identical trimmed queries are collected once.

## `targetDomain` (type: `string`):

Optional hostname or HTTP(S) URL. When provided, the Actor returns one domain-rank record per query and stops after the first matching organic result. Leave empty to return all organic results.

## `startPage` (type: `integer`):

First Google results page to scrape (1 = positions 1–10).

## `endPage` (type: `integer`):

Last Google results page to scrape. E.g. startPage=1, endPage=3 scrapes pages 1, 2 and 3 (positions 1–30).

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

Language code for the search (select a language from the list).

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

Target country used to localize the search results (select a country from the list).

## Actor input object example

```json
{
  "queries": [
    "apify web scraping"
  ],
  "targetDomain": "",
  "startPage": 1,
  "endPage": 1,
  "language": "en",
  "country": "us"
}
```

# Actor output Schema

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

Organic Google SERP results or one domain-rank record per query.

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

Final status, requested, successful, failed, and remaining pages, result count, selected market, and spending-limit state.

# 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": [
        "apify web scraping"
    ],
    "targetDomain": "",
    "startPage": 1,
    "endPage": 1,
    "language": "en",
    "country": "us"
};

// Run the Actor and wait for it to finish
const run = await client.actor("datascraperes/google-serp-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": ["apify web scraping"],
    "targetDomain": "",
    "startPage": 1,
    "endPage": 1,
    "language": "en",
    "country": "us",
}

# Run the Actor and wait for it to finish
run = client.actor("datascraperes/google-serp-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": [
    "apify web scraping"
  ],
  "targetDomain": "",
  "startPage": 1,
  "endPage": 1,
  "language": "en",
  "country": "us"
}' |
apify call datascraperes/google-serp-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datascraperes/google-serp-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/hrhVFW4C2RI1ENViU/builds/3mjDKlQMEXHlSQVst/openapi.json
