# Google Search Scraper (`badr_xba/google-search-scraper`) Actor

Google results from any country domain with the real destination URL resolved, plus the people-also-ask and related-search blocks. Positions are compared between runs for the domains you track, so it doubles as a rank tracker. Example: two keywords on google.fr, scheduled weekly.

- **URL**: https://apify.com/badr\_xba/google-search-scraper.md
- **Developed by:** [Badr Bouargan](https://apify.com/badr_xba) (community)
- **Categories:** SEO tools, Marketing
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 scraped search result pages

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

## Google Search Scraper with Rank Tracking

![Google Search Scraper](https://api.apify.com/v2/key-value-stores/paDGjcmD1ZMsRJLZS/records/google-search-banner.png?signature=18GUCXsyUQ8HKIqvGEI48)

Scrape **Google search results** — organic results, ads, *People Also Ask* and related searches — for **any query, from any country, in any language**. The Actor remembers positions between runs and tells you which of your pages moved up and which moved down.

### What you can do with it

- **Track your rankings**: list your domains, schedule a daily run, and read the gains and losses in a column.
- **Watch competitors**: see who occupies the top ten on your money keywords, and when that changes.
- **Do keyword research**: *People Also Ask* questions and related searches come with every page.
- **Build link prospect lists**: the exact URL of every result, not just the homepage.
- **Compare markets**: the same keyword through 33 national Googles, desktop or mobile.

No API key. Requests go through Apify's Google SERP proxy.

### Why this Actor

- **Any search, anywhere.** 33 country domains are in the list (`google.com`, `google.co.uk`, `google.de`, `google.co.jp`, `google.com.br`, `google.ma`…), and any other works by pasting a full Google URL.
- **Exact result URLs.** Google now hides every result link behind an encrypted redirect. This Actor follows Google's own redirect for each result, so you get `https://site.com/the/real/page`, not just the homepage.
- **Rank tracking built in.** For the domains you follow, every row carries the previous position, the change and the movement label.
- **Mobile or desktop**, with country and language control.

### How it works

1. Each query becomes a Google results page request through the SERP proxy.
2. The page is parsed structurally — by links, headings and blocks, never by CSS class names, which Google changes constantly.
3. Every result's redirect is resolved to its true destination in parallel, outside the SERP proxy, which keeps that step nearly free.
4. Tracked domains are compared with the previous run, stored in a named key-value store that survives runs.

### Step-by-step tutorial

1. Put one query per line in **Queries**, or paste a full Google URL to reuse your own parameters.
2. Pick a **Google domain**, and optionally a **Country** and **Language** (`gl` and `hl`).
3. Set **Pages per query** — about ten results per page, so 3 pages gives the top 30.
4. To follow your own site, list it in **Tracked domains** (`example.com`) and create an Apify **Schedule** to run daily.
5. Press **Start**, then export as Excel, CSV or JSON.

### Input example

```json
{
  "queries": ["best running shoes", "trail running shoes review"],
  "googleDomain": "www.google.com",
  "countryCode": "us",
  "languageCode": "en",
  "maxPagesPerQuery": 3,
  "trackedDomains": ["example.com"],
  "mobileResults": false
}
```

### Output example

![Sample output](https://api.apify.com/v2/key-value-stores/paDGjcmD1ZMsRJLZS/records/google-search-output.png?signature=BSyokHbm0QZHY91Kk3AT)

Every row as JSON:

```json
{
  "query": "best running shoes",
  "page": 1,
  "position": 2,
  "type": "organic",
  "title": "What are the best running shoes that you'd actually buy?",
  "url": "https://www.reddit.com/r/runninglifestyle/comments/1u5x7mx/what_are_the_best_running_shoes/",
  "domain": "reddit.com",
  "description": "Jun 15, 2026 · The Asics Superblast 2 are the most well made running shoes…",
  "isExactUrl": true,
  "previousPosition": 5,
  "positionChange": 3,
  "rankMovement": "up",
  "peopleAlsoAsk": ["Which running shoe brand is best?"],
  "relatedQueries": ["best running shoes for flat feet"]
}
```

The **Rank tracking** dataset view shows only the tracked domains with their movement.

### Pricing

Pay per result page scraped, shown on the Actor's pricing tab, plus a small per-run fee. Platform costs — the Google SERP proxy and compute — are included, so there is nothing else to pay. About ten results per page.

### FAQ

**Why do some rows have `isExactUrl: false`?** Google's redirect could not be followed for that result, so the address was rebuilt from the text Google displays. Domain, title, position and snippet remain correct.

**Are ads always included?** They are collected when Google shows them, but the no-JavaScript layout the Actor reads does not always contain them.

**How does rank tracking start?** The first run records positions; from the second run on you get `previousPosition`, `positionChange` and `rankMovement`. Use a Schedule for a daily history.

**Can I scrape a country that is not in the list?** Yes — paste the full Google URL (for example `https://www.google.com.sg/search?q=...&hl=en`) as a query.

**Why is the Google SERP proxy required?** Google returns no usable results to ordinary datacenter addresses; this was tested. The proxy group is preselected for you.

### Integrations

- **Schedules**: a daily run builds your own rank-tracking history, without a subscription to an SEO suite.
- **API**: pull each run's dataset as JSON, CSV or Excel.
- **Webhooks**: notify your service, or your Slack, as soon as positions change.
- **No-code tools**: Google Sheets, Zapier and Make from the Integrations tab.

### Support

Open an issue on the Actor's **Issues** tab for a bug, a missing SERP feature or a country that misbehaves.

**Did this Actor do the job?** Leaving a short review on its Store page takes a minute and helps other people find it — and tells me which feature to build next.

### Legal

This Actor reads **public** search result pages, the same ones any visitor sees, and collects no personal data. Automated access may conflict with Google's Terms of Service; how you use the results is your responsibility.

### En français

Récupère les résultats de recherche Google — résultats naturels, annonces, « Autres questions posées » et recherches associées — pour **n'importe quelle recherche, depuis n'importe quel pays et dans n'importe quelle langue** (33 Google nationaux, et n'importe quel autre en collant son URL). Google chiffre désormais l'adresse de chaque résultat : l'Actor suit la redirection de Google pour restituer l'**adresse exacte** de la page, pas seulement le domaine. Il mémorise les positions d'un run à l'autre et signale ce qui monte et ce qui baisse pour les domaines suivis. Aucune clé API.

# Actor input Schema

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

One search per line. You can also paste a full Google URL (https://www.google.fr/search?q=...) to reuse your own parameters.

## `googleDomain` (type: `string`):

Which national Google to query. The domain changes the results a lot: google.de does not answer like google.com. Country missing from the list? Paste a full Google URL in Search queries instead.

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

Two-letter country code (Google's “gl” parameter): us, gb, de, fr, br, in, ma… Leave empty not to force a country.

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

Two-letter language code (Google's “hl” parameter): en, es, de, fr, pt, ar, ja… Leave empty for the domain default.

## `locationUule` (type: `string`):

Optional, for local searches: the UULE code of a city. Leave empty if you do not know what it is.

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

How many result pages to read for each search. Expect about ten results per page.

## `mobileResults` (type: `boolean`):

Switch on to see the ranking as it appears on a phone, which often differs from desktop.

## `includePaidResults` (type: `boolean`):

Adds sponsored listings to the organic results. Note that the no-JavaScript page the Actor reads does not always show ads.

## `oneRowPerResult` (type: `boolean`):

On: each result is a row, ready for a spreadsheet. Off: one row per result page, with the results nested inside.

## `trackedDomains` (type: `array`):

Your sites, or your competitors’. For these domains the Actor adds the previous position and the movement since the last run.

## `trackRankChanges` (type: `boolean`):

Remembers positions between runs to report gains and losses. Most useful with a daily schedule.

## `maxAttemptsPerPage` (type: `integer`):

How many times to retry when Google does not answer or returns an error. Each attempt uses one SERP proxy request.

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

How many of your queries run in parallel. Google's SERP proxy takes several seconds per page, so running queries one after another wastes most of the run. Ten was the fastest setting measured — 100 results a minute, against 83 at sixteen and 68 at five: past ten, Google slows the proxy down and the retries eat the gain. Each query still reads its own pages in order.

## `includeHtml` (type: `boolean`):

Stores Google's original page in the run's storage. For troubleshooting only: it makes runs much heavier.

## `proxyConfiguration` (type: `object`):

Google blocks datacenter servers. Keep the GOOGLE\_SERP group: it is Apify's proxy built for Google Search, and it is included in your plan.

## Actor input object example

```json
{
  "queries": [
    "best running shoes",
    "coffee shop new york"
  ],
  "googleDomain": "www.google.com",
  "countryCode": "",
  "languageCode": "",
  "locationUule": "",
  "maxPagesPerQuery": 1,
  "mobileResults": false,
  "includePaidResults": true,
  "oneRowPerResult": true,
  "trackedDomains": [
    "example.com"
  ],
  "trackRankChanges": true,
  "maxAttemptsPerPage": 3,
  "maxConcurrency": 10,
  "includeHtml": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "GOOGLE_SERP"
    ]
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

Tableau : recherche, position, titre, domaine, lien et résumé.

## `rankTracking` (type: `string`):

Position actuelle, position précédente et mouvement pour les domaines suivis.

## `allFields` (type: `string`):

Données complètes, y compris annonces, questions associées et recherches liées.

## `runStats` (type: `string`):

Pages parcourues, résultats naturels, annonces et échecs éventuels.

# 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",
        "coffee shop new york"
    ],
    "trackedDomains": [
        "example.com"
    ],
    "maxConcurrency": 10,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "GOOGLE_SERP"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("badr_xba/google-search-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",
        "coffee shop new york",
    ],
    "trackedDomains": ["example.com"],
    "maxConcurrency": 10,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["GOOGLE_SERP"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("badr_xba/google-search-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",
    "coffee shop new york"
  ],
  "trackedDomains": [
    "example.com"
  ],
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "GOOGLE_SERP"
    ]
  }
}' |
apify call badr_xba/google-search-scraper --silent --output-dataset

```

## MCP server setup

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