# Google Search Results Scraper (SERP) (`barefoot_grade/google-search-results-scraper`) Actor

Collect Google Search results for any query, country and language. One row per results page: every organic result's position, title, real link, displayed link, site, snippet, date and sitelinks, plus People also ask and related searches. Pages up to your cap; failed pages are reported, not charged.

- **URL**: https://apify.com/barefoot_grade/google-search-results-scraper.md
- **Developed by:** [Philip Kirkbride](https://apify.com/barefoot_grade) (community)
- **Categories:** SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 results

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 Search Results Scraper (SERP)

Turn any Google search into clean, structured rows. Type the searches you care about, pick a country and language, and every Google results page becomes one row: each organic result's position, title, real destination link, the green breadcrumb Google displays, the site name, the snippet and its date, plus sitelinks, the "People also ask" questions and the related searches at the bottom of the page.

Read one page per search or follow Google's own "Next" pages up to ten deep, with a total page cap so a long list of searches never runs away. Pages that cannot be read are listed in the run summary and are not charged.

### Use cases

- **Rank tracking**: where a domain appears for a set of keywords, page by page, in a chosen country.
- **SEO research**: titles, snippets and displayed breadcrumbs of the pages that win a search.
- **Content ideas**: "People also ask" questions and related searches for a topic.
- **Competitor monitoring**: re-run the same searches on a schedule and compare positions over time.
- **Lead and link discovery**: the real destination links of the top results for niche searches.

### Quick Start

```json
{
  "queries": ["best running shoes", "how to make cold brew coffee"],
  "countryCode": "us",
  "languageCode": "en",
  "maxPagesPerQuery": 1,
  "maxPages": 100
}
```

Each search is one Google search. Set `maxPagesPerQuery` to read results past the first ten; paging stops by itself when Google has no further page.

### Input

| Input | Type | Default | Meaning |
| --- | --- | --- | --- |
| `queries` | array | required | What to search for, one search per line, exactly as you would type it into Google. A Google search link (`google.com/search?q=...`) also works. Repeated searches are read once. |
| `countryCode` | string | `us` | Two-letter country code for the results (`us`, `gb`, `de`, `fr`, `ca`, `au`, `in`, ...). |
| `languageCode` | string | `en` | Interface and results language (`en`, `de`, `fr`, `es`, `pt-BR`, ...). |
| `maxPagesPerQuery` | integer | `1` | Result pages to read per search, 1 to 10 (about 10 organic results each). |
| `maxPages` | integer | `100` | Total cap on result pages (dataset rows) across every search, up to 5,000. |
| `maxConcurrency` | integer | `4` | Searches that run side by side, 1 to 6. Lower is gentler, higher is faster. |

### Example queries

- `{"queries": ["crm software for small business"], "maxPagesPerQuery": 3}`
- `{"queries": ["beste laufschuhe", "kaffeemühle test"], "countryCode": "de", "languageCode": "de"}`
- `{"queries": ["plumber near denver", "emergency plumber denver"], "countryCode": "us"}`
- `{"queries": ["https://www.google.com/search?q=python+list+comprehension"]}`

### What it returns

The dataset contains one row per Google results page:

| Field | Meaning |
| --- | --- |
| `searchQuery` | The search the row came from: `term`, `page` (1-based), `countryCode`, `languageCode`. |
| `url` | The Google results page that was read. |
| `resultsCount` | Number of organic results on the page. |
| `organicResults` | The organic results in page order (see below). |
| `peopleAlsoAsk` | The "People also ask" questions on the page, as `{"question": ...}`. Empty when Google shows none. |
| `relatedQueries` | The related searches at the bottom of the page, each with a ready-to-use Google link for the same country and language. |
| `hasNextPage` | Whether Google offers a further results page. |
| `unresolvedUrls` | Organic results on this page whose `url` is null (normally 0). |
| `scrapedAt` | Collection time (UTC, ISO 8601). |
| `error` | Always `null` in the dataset. Pages that could not be read are listed in the run summary instead. |

Each entry of `organicResults` has:

| Field | Meaning |
| --- | --- |
| `position` | 1-based rank on the page. Video and forum results that Google lists among the organic results are included in order. |
| `title` | The result title. |
| `url` | The result's real destination link. |
| `displayedUrl` | The green breadcrumb Google shows under the title (for example `https://www.w3schools.com › python › ...`), when it is a web address. |
| `siteName` | The site, channel or community name Google shows above the title (for example `Reddit · r/howto`). |
| `snippet` | The description under the title. |
| `date` | The date Google prints before the snippet, such as `May 7, 2026` or `3 days ago`, when there is one. |
| `sitelinks` | Extra links Google shows under a result (mostly for brand searches), each with `title`, `url` and `snippet`. |

Ads, maps, shopping carousels and image packs are not included. The run summary (`OUTPUT`) reports `pages` (rows delivered), `organicResults`, and any pages that could not be read in `pageErrors`, each with a short code and message (for example `BLOCKED`, `LAYOUT_CHANGED` or `NETWORK_ERROR`).

### Output example

```json
{
  "searchQuery": {
    "term": "how to compost at home",
    "page": 1,
    "countryCode": "us",
    "languageCode": "en"
  },
  "url": "https://www.google.com/search?q=how+to+compost+at+home&hl=en&gl=us",
  "resultsCount": 8,
  "organicResults": [
    {
      "position": 1,
      "title": "Composting At Home | US EPA",
      "url": "https://www.epa.gov/recycle/composting-home",
      "displayedUrl": "https://www.epa.gov › recycle › composting-home",
      "siteName": "U.S. Environmental Protection Agency (.gov)",
      "snippet": "Start your pile with a four- to six-inch layer of bulky browns such as twigs and wood chips. Then layer your greens and browns like lasagna. If ...",
      "date": "Dec 8, 2025",
      "sitelinks": []
    },
    {
      "position": 2,
      "title": "How to Make Compost at Home - UMD Extension",
      "url": "https://extension.umd.edu/resource/how-make-compost-home",
      "displayedUrl": "https://extension.umd.edu › resource › how-make-com...",
      "siteName": "UMD Extension",
      "snippet": "Dig a trench or hole in a garden bed about eight to twelve inches deep. Bury your kitchen waste (fruit and vegetable peelings and cores, coffee ...",
      "date": "Jul 12, 2024",
      "sitelinks": []
    }
  ],
  "peopleAlsoAsk": [
    {
      "question": "What is the laziest way to compost?"
    },
    {
      "question": "What are 5 items that should not be composted?"
    }
  ],
  "relatedQueries": [
    {
      "query": "Compost bin",
      "url": "https://www.google.com/search?q=Compost+bin&hl=en&gl=us"
    },
    {
      "query": "How to compost at home for beginners",
      "url": "https://www.google.com/search?q=How+to+compost+at+home+for+beginners&hl=en&gl=us"
    }
  ],
  "hasNextPage": true,
  "unresolvedUrls": 0,
  "scrapedAt": "2026-10-20T00:00:03Z",
  "error": null
}
```

### Price

**$0.0015 per results page** delivered (one dataset row, up to about 10 organic results), plus **$0.005 per run start**. The run-start event is charged per GB of memory; the default 4096 MB run is four start events ($0.02). The start is charged even if the run saves no results. Pages that could not be read are not charged. Platform usage is included in these prices.

### Good to know

- Google personalizes and localizes results, so positions can differ slightly from what you see when signed in to your own Google account. Results here are what a signed-out visitor in the chosen country sees.
- Google usually shows 8 to 10 organic results per page; some pages show fewer when videos or other blocks take the space.
- "People also ask" lists the questions only; the expandable answers are not included.
- If Google temporarily limits requests, the run retries with growing pauses and reports any page it could not finish in `OUTPUT.pageErrors`; pages already collected are kept. If no page at all can be read, the run fails with a clear message.

# Actor input Schema

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

What to search for, one search per line, exactly as you would type it into Google. A Google search link (google.com/search?q=...) also works.

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

Two-letter country code for the results, such as us, gb, de, fr, ca, au or in. Results are localized for that country.

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

Interface and results language code, such as en, de, fr, es or pt-BR.

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

How many Google result pages to read per search (about 10 organic results each). Paging stops early when Google has no next page.

## `maxPages` (type: `integer`):

Total cap on result pages (dataset rows) across every search.

## `maxConcurrency` (type: `integer`):

How many searches run side by side. Higher is faster; lower is gentler.

## Actor input object example

```json
{
  "queries": [
    "best running shoes",
    "how to make cold brew coffee"
  ],
  "countryCode": "us",
  "languageCode": "en",
  "maxPagesPerQuery": 1,
  "maxPages": 100,
  "maxConcurrency": 4
}
```

# Actor output Schema

## `results` (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": [
        "best running shoes",
        "how to make cold brew coffee"
    ],
    "countryCode": "us",
    "languageCode": "en",
    "maxPagesPerQuery": 1,
    "maxPages": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("barefoot_grade/google-search-results-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": [
        "best running shoes",
        "how to make cold brew coffee",
    ],
    "countryCode": "us",
    "languageCode": "en",
    "maxPagesPerQuery": 1,
    "maxPages": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("barefoot_grade/google-search-results-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": [
    "best running shoes",
    "how to make cold brew coffee"
  ],
  "countryCode": "us",
  "languageCode": "en",
  "maxPagesPerQuery": 1,
  "maxPages": 100
}' |
apify call barefoot_grade/google-search-results-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,barefoot_grade/google-search-results-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/MlG13qBc3S7sP1Bmy/builds/IsUzCKdlbH8S8qCEA/openapi.json
