# Google Search Scraper: organic SERP results for rank tracking at scale

Apidojo Google Search Scraper is a SERP API that returns Google organic results for a keyword or a search URL. It costs $0.002 per query with the first 10 results included, then $0.0002 per further result, targets 240 countries and 36 languages, returns desktop or mobile SERPs, and has no daily query cap.

[Check your first keyword](https://apify.com/apidojo/google-search-scraper)

[See sample output](#output)

Free Apify plan: 5 runs a month, 10 items a run. No credit card.

**$0.002** per query, 10 results in

**240** countries targetable

**0** daily query cap

**$2** per 1,000 keywords checked

$2 per 1,000 is the top-ten check most rank tracking runs: one query per keyword, ten results, nothing extra. Read on 21 September 2026.

## What are the Google Search Scraper specifications?

Google Search Scraper accepts keywords or Google search URLs, targets 240 countries and 36 languages, returns desktop or mobile SERPs, and pages as deep as you set. Each result is a normalised record of title, link, visible link and snippet.

**What it returns:** Google organic results, title, link, visible link and snippet, one record per result

**Inputs:** searchTerms or startUrls; countryCode, languageCode, maxItems, maxPagesPerQuery, mobileResults, customMapFunction

**Price:** $0.002 per query with the first 10 results included, then $0.0002 per further result

**Countries:** 240, each switching the Google domain as well as the region, google.es for Spain

**Languages:** 36, restricting results to pages written in that language

**Device:** Desktop by default; mobileResults returns the mobile SERP layout

**Depth:** maxPagesPerQuery, prefilled at 10. Google serves roughly 200 results for a query

**Required input:** countryCode. Everything else has a default

**Ranking position:** Not a field. It is the order of the dataset, see the section below

**Paid SERP features:** None. Ads, shopping, People Also Ask, AI Overviews and the local pack are not returned

**Output shaping:** customMapFunction, one synchronous JavaScript function per record

**Export formats:** JSON, JSONL, CSV, Excel, XML, HTML table, API

**Login, proxy or API key:** None required

**Free plan:** Demo mode, 5 runs per month, 10 items per run

**Daily cap:** None. Your Apify plan is the only ceiling

## What does Google Search Scraper output look like?

Google Search Scraper output is one JSON object per organic result, carrying four fields: title, link, visible\_link and snippet, plus a type discriminator. It is deliberately small. Every field is one an SEO report actually uses.

**Keyword**

**Keyword batch**

**Search URL**

**Reshaped**

Runs on apidojo/google-search-scraper

One query, ten results, $0.002. This is the shape of a rank check.

Input

```
{
  "searchTerms": ["project management software"],
  "countryCode": "us",
  "languageCode": "en",
  "maxPagesPerQuery": 1
}
```

Output

```
{
  "type": "searchResult",
  "title": "Welcome to Python.org",
  "link": "https://www.python.org/",
  "visible_link": "www.python.org",
  "snippet": "A programming language that lets you work quickly."
}
```

Runs on apidojo/google-search-scraper

Results arrive grouped by term, in the order the terms were given.

Input

```
{
  "searchTerms": [
    "project management software",
    "task tracker for teams",
    "gantt chart tool"
  ],
  "countryCode": "gb",
  "maxPagesPerQuery": 1
}
```

Output

```
{
  "type": "searchResult",
  "title": "Welcome to Python.org",
  "link": "https://www.python.org/",
  "visible_link": "www.python.org",
  "snippet": ""
}
```

Runs on apidojo/google-search-scraper

Paste a Google search URL to keep operators, tbs filters or a site: restriction.

Input

```
{
  "startUrls": [
    "https://www.google.com/search?q=site%3Aexample.com+pricing"
  ],
  "countryCode": "us",
  "maxPagesPerQuery": 5
}
```

Output

```
{
  "type": "searchResult",
  "title": "Pricing, Example",
  "link": "https://example.com/pricing",
  "visible_link": "example.com › pricing",
  "snippet": "Plans from $0 to $99 a month."
}
```

Runs on apidojo/google-search-scraper

customMapFunction adds, changes or removes a field. Return undefined to drop one.

Input

```
(object) => ({
 ...object,
  title: object.title?.toUpperCase() || null,
  sourceDomain: object.visible_link || null,
  snippet: undefined
})
```

Output

```
{
  "type": "searchResult",
  "title": "WELCOME TO PYTHON.ORG",
  "link": "https://www.python.org/",
  "visible_link": "www.python.org",
  "sourceDomain": "www.python.org"
}
```

### What the fields are

-   #### The result

    Title as Google renders it, and the destination URL

-   #### The display URL

    visible\_link, the breadcrumb Google shows, which is not always the link

-   #### The snippet

    Google’s description text, empty when Google renders none

-   #### What you add

    Position from dataset order, and any field your map function returns

| Field | Type | Example value | Group |
| --- | --- | --- | --- |
| type | string | searchResult | Record |
| title | string | Welcome to Python.org | Record |
| link | string | https://www.python.org/ | Record |
| visible_link | string | www.python.org | Record |
| snippet | string, can be empty | A programming language that lets you work quickly. | Record |

## How do you get the ranking position?

Google Search Scraper does not return a position field. Rank is the order of the dataset: the first record for a query is position 1. Number the records as they arrive and you have a rank column, four lines of code, and the reason this page says so is that nothing on the actor’s own listing does.

1.  01

    ### One query per run, or one query per term

    Results are written in the order Google served them, grouped by search term in the order you listed them. Keep one term per run while you are learning the shape, then batch once you trust it.

2.  02

    ### Number as you read, not after

    Enumerate the dataset in iteration order. Sorting, filtering or de-duplicating first destroys the only thing that encodes rank.

3.  03

    ### Reset the counter on each term

    In a batch run the records for the second term follow the first without a separator, so track the term yourself, or set includeSearchKeywords-style context with a map function that stamps the term onto every row.

4.  04

    ### Store the date with the rank

    A position is meaningless without when and where it was measured. Write countryCode, languageCode, device and the run date alongside it, or next month’s comparison is not a comparison.

```
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

TERM = "project management software"

run = client.actor("apidojo/google-search-scraper").call(run_input={
    "searchTerms": [TERM],
    "countryCode": "us",
    "languageCode": "en",
    "maxPagesPerQuery": 1,
})

# Rank is position in the dataset. Enumerate in iteration order, do not sort.
for position, item in enumerate(
    client.dataset(run.default_dataset_id).iterate_items(), start=1
):
    print(position, item["visible_link"], item["link"])
```

One caveat worth stating plainly: because ads and the paid or feature blocks are not returned, this position is the organic rank, not where the result sits on the rendered page. For share-of-voice work that distinction matters, and no scraper that returns only organic results can close it.

## How much does Google Search Scraper cost?

Google Search Scraper costs $0.002 per query with the first 10 results included, then $0.0002 per further result. Checking 1,000 keywords to depth ten costs $2.00. The formula is $0.002 × queries + $0.0002 × (results − 10 × queries).

$0.002per query, 10 results in

-   Then $0.0002 for each result past the tenth
-   No per-run fee and no daily cap
-   A top-ten check on 1,000 keywords is $2.00

[Check your first keyword](https://apify.com/apidojo/google-search-scraper)

The whole price, as arithmetic

`$0.002 × queries` + `$0.0002 × (results − 10 × queries)`

One query is one search term, or one search URL. The ten results it includes are per query, not per run, so a hundred keywords checked to depth ten spend a hundred query fees and nothing else.

| Job | Calculation | Cost |
| --- | --- | --- |
| 1 keyword, top 10 | $0.002 | $0.002 |
| 1 keyword, 100 results | $0.002 + 90 × $0.0002 | $0.020 |
| 1 keyword, 1,000 results | $0.002 + 990 × $0.0002 | $0.200 |
| 5 keywords, 500 results | 5 × $0.002 + 450 × $0.0002 | $0.100 |
| 1,000 keywords, top 10 each | 1,000 × $0.002 | $2.00 |
| 1,000 keywords, daily for a month | 30 × $2.00 | $60.00 |
| 500 keywords × 4 countries, top 10 | 2,000 × $0.002 | $4.00 |
| 10,000 keywords, top 20 each | 10,000 × $0.002 + 100,000 × $0.0002 | $40.00 |

The README’s own examples for "1,000 results" and "5 keywords, 500 results" do not match its formula, they subtract 100 free results instead of 10. The figures above are computed from the event prices the Apify Store API reports, which are the ones you are billed at. Free plan runs in demo mode: 5 runs a month, 10 items a run.

## How does it compare with Google’s Custom Search JSON API?

Google’s Custom Search JSON API is closed to new customers, and Google’s own documentation gives existing customers until 1 January 2027 to move to something else. While it lasts it allows 100 free queries a day, charges $5 per 1,000 after that, caps at 10,000 queries a day, and never returns more than 100 results for a query.

|  | Apidojo Google Search Scraper | Google Custom Search JSON API |
| --- | --- | --- |
| Still open | Yes | Closed to new customers. Existing ones have until 1 January 2027 |
| What it searches | google.com as a visitor sees it, per country domain | A Programmable Search Engine you configure; full web search requires contacting Google |
| Setup | An Apify account | Google account, Cloud project, API key and a search engine to configure |
| Free allowance | Demo mode: 5 runs a month, 10 items a run | 100 queries a day |
| Price after that | $0.002 per query, 10 results included, $2 per 1,000 | $5 per 1,000 queries |
| Results per request | As deep as maxPagesPerQuery allows | num caps at 10 |
| Results per query, total | Roughly 200, what Google serves | 100, hard limit, start + num above 100 is an error |
| Daily ceiling | None beyond your Apify plan | 10,000 queries a day |
| Country and language | 240 countries, 36 languages | gl and lr parameters |
| Mobile SERP | mobileResults switch | Not offered |
| Cost of 1,000 keywords at top 10 | $2.00 | $5.00, and 1,000 of the day’s 10,000 queries |

Every figure in the right-hand column is quoted from Google’s Custom Search JSON API overview and its cse.list reference, read on the snapshot date. The overview carries the closure notice and the 1 January 2027 date; the reference states that num caps at 10 and that "the JSON API will never return more than 100 results, even if more than 100 documents match the query". Google names Vertex AI Search as the successor for searching up to 50 domains, and asks anyone who needs full web search to contact them.

## How to scrape Google Search with Apidojo in 4 steps

Scraping Google with Apidojo takes 4 steps: open the scraper, paste keywords or a search URL, set the country and depth, then run and export. No API key, Cloud project or search engine configuration is involved.

1.  01

    ### Open Google Search Scraper on Apify

    Sign in with a free Apify account. No credit card is needed to run it in demo mode.

2.  02

    ### Paste keywords or a search URL

    Put terms in searchTerms, or paste Google search URLs into startUrls to keep operators such as site: or a tbs filter.

3.  03

    ### Set country, language and depth

    countryCode is required and also picks the Google domain. Add languageCode, switch mobileResults on for the mobile SERP, and set maxPagesPerQuery for depth.

4.  04

    ### Run and export the dataset

    Download CSV for a spreadsheet, or read the results through the Apify API and number them to get rank.

### Which inputs and filters it accepts

| Input | What it does | Example |
| --- | --- | --- |
| searchTerms | Keywords to search, one query each | ["project management software", "gantt chart tool"] |
| startUrls | Google search URLs, so operators and filters survive | google.com/search?q=site:example.com+pricing |
| countryCode | Required. Region and Google domain, es gives google.es | us · gb · de · tr · br |
| languageCode | Restricts results to pages in that language | en · de · tr · es |
| mobileResults | Returns the mobile SERP instead of desktop | true |
| maxPagesPerQuery | How deep to page. Google serves roughly 200 results | 1 for a top-ten check, 10 for depth |
| maxItems | Hard cap on results across the whole run | 10000 |
| customMapFunction | Reshapes each record, add, change or remove a field | (o) => ({...o, domain: o.visible_link }) |

-   #### `countryCode does two things`

    It sets the region Google searches for and the domain it searches on, es means google.es, not google.com with a Spanish preference. That is why a country switch can move a ranking more than a language switch does, and why a single run cannot represent two markets.

-   #### `Use startUrls to keep your operators`

    searchTerms sends a plain query. Anything you would type into Google, site:, inurl:, a quoted phrase, a tbs date filter, survives only if you build the search URL yourself and paste it into startUrls. For a technical audit that is usually the input you want.

## How do you call the Google Search Scraper API?

Google Search Scraper is the actor apidojo/google-search-scraper, called through the Apify REST API or the official Python and JavaScript clients. A rank check is three fields: the term, the country, and one page of depth.

**Rank tracking**

**Share of voice**

**cURL**

**MCP**

```
from apify_client import ApifyClient
from datetime import date

client = ApifyClient("YOUR_APIFY_TOKEN")

TERMS = ["project management software", "task tracker for teams"]
DOMAIN = "example.com"

run = client.actor("apidojo/google-search-scraper").call(run_input={
    "searchTerms": TERMS,
    "countryCode": "us",
    "languageCode": "en",
    "maxPagesPerQuery": 1,
})

# 20 records: ten for the first term, then ten for the second.
rows = list(client.dataset(run.default_dataset_id).iterate_items())
for i, term in enumerate(TERMS):
    page = rows[i * 10:(i + 1) * 10]
    hit = next((n for n, r in enumerate(page, 1) if DOMAIN in r["link"]), None)
    print(date.today(), term, hit or "not in top 10")
```

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

// Who owns the top ten across a keyword set
const run = await client.actor('apidojo/google-search-scraper').call({
  searchTerms: ['serp api', 'google scraper', 'rank tracking api'],
  countryCode: 'us',
  maxPagesPerQuery: 1,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
const share = {};
for (const r of items) {
  const host = new URL(r.link).hostname.replace(/^www\./, '');
  share[host] = (share[host] ?? 0) + 1;
}
console.log(Object.entries(share).sort((a, b) => b[1] - a[1]).slice(0, 10));
```

```
curl -X POST \
  "https://api.apify.com/v2/acts/apidojo~google-search-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchTerms":["serp api"],"countryCode":"us","languageCode":"en","maxPagesPerQuery":1}'
```

```
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com/?tools=apidojo/google-search-scraper",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

-   ### n8n

    A weekly keyword run writing into a rank table.

-   ### Looker Studio

    CSV export as a ranking dashboard source.

-   ### Warehouse

    JSONL into BigQuery, one row per result per day.

-   ### Webhooks

    POST to any URL when a run finishes.

## What can you build with Google SERP data?

SERP data powers 6 SEO workflows: rank tracking, share of voice, competitor content mapping, keyword research, per-market comparison and citation monitoring. Each one names the input, the field it reads and what comes out.

-   ### Rank tracking

    `Your keyword set · one page · daily or weekly`

    **link matched against your domain, position from dataset order** Fields

-   ### Share of voice

    `A keyword set · top ten · one country`

    **visible_link, counted by host** Fields

-   ### Competitor content mapping

    `startUrls with site:competitor.com`

    **title and link for every indexed page Google will show** Fields

-   ### Keyword research at ten a penny

    `A long keyword list · one page each`

    **title and snippet, read for intent and phrasing** Fields

-   ### Per-market comparison

    `The same keyword × countryCode us, gb, de, tr`

    **overlap between the top tens** Fields

-   ### Citation monitoring

    `Brand and product terms · weekly`

    **link and snippet, watched for the sources that rank above you** Fields

## What are the limits of Google Search Scraper?

Google Search Scraper returns organic results and nothing else. Six limits below matter before you plan a report around it, the first two are the ones people discover late.

-   ### No SERP features at all

    Ads, shopping, the local pack, People Also Ask, featured snippets, knowledge panels, video carousels and AI Overviews are not in the output. What comes back is the organic list.

    Treat the position as organic rank. For pixel position or feature presence you need a rendered-SERP product, which this is not.

-   ### No position field

    Rank is the order of the dataset, not a value on the record. Anything that reorders the rows before you number them loses it.

    Enumerate on read. The rank section above has the four lines.

-   ### No result count and no date

    Google’s "about 12,300,000 results" line and any result timestamp are not returned. Neither is the query, so a batch run does not label which term a row belongs to.

    Stamp the term, country, device and run date on each row with customMapFunction, or track them by position in the batch.

-   ### snippet can be empty

    Google renders no description for some results, and the field comes back as an empty string rather than being absent.

    Test for empty, not for missing, before you write it into a report.

-   ### Roughly 200 results per query

    That is what Google itself serves for a query, so paging deeper returns nothing new however high maxPagesPerQuery goes.

    For more coverage, split the query, by site:, by country, or into narrower terms.

-   ### Personalisation and volatility

    Two runs minutes apart can differ. Google varies results by data centre, time and test bucket, and the actor holds no session that would stabilise them.

    Measure on a fixed schedule and compare trends, never two single runs.

## How reliable is Google Search Scraper?

Google Search Scraper ran 11,744 times in the last 30 days at a 95.8% success rate. That is the lowest success rate in the Apidojo catalogue, which averages 99.7%, and it is published here rather than left off the page.

**1,248** users on Apify

**59,027** runs, all time

**95.8%** run success, 30 days

**3.9 / 5** from 11 Apify reviews

Success is succeeded ÷ succeeded + failed + timed out; 481 of 11,744 runs failed. Google defends its result pages more actively than any other source in the catalogue, and this is what that costs. Plan retries into anything scheduled, and check the run log rather than assuming an empty dataset means an empty SERP. Read on 21 September 2026.

## Is it legal to scrape Google search results?

Collecting publicly visible search results without logging in is generally lawful in the United States. US courts have held that scraping public pages does not breach the Computer Fraud and Abuse Act, in hiQ Labs v. LinkedIn (9th Cir., 2022). Google’s Terms of Service are a separate, contractual matter from that statute.

-   ### What the scraper reads

    Public, logged-out result pages. No Google account, no session and no authentication is involved, so nothing gated is reached.

-   ### Terms of Service are not the CFAA

    hiQ addressed a criminal statute, not a contract. Google’s terms discourage automated querying, and that risk is a commercial judgement for you to make, not one this page can make for you.

-   ### Snippets are other people’s text

    A snippet is an extract of somebody’s page, and titles are theirs too. Analysing them is one thing; republishing a corpus of them is a copyright question worth asking first.

This is general information, not legal advice.

## Google Search Scraper frequently asked questions

### Everything else people ask

Fifteen questions about this scraper and its family. Anything about the wider catalogue is answered on the scrapers hub.

[All 26 scrapers](/scrapers/)

### Does Google Search Scraper return the ranking position?

Not as a field. Position is the order of the dataset, the first record for a query is position 1. Number the records as you read them, before sorting or filtering anything.

### Does it return ads, People Also Ask or AI Overviews?

No. The output is organic results only: title, link, visible link and snippet. No ads, shopping, local pack, featured snippet, knowledge panel or AI Overview is returned.

### How many results can it return for one keyword?

About 200, which is what Google itself serves for a query. Set maxPagesPerQuery for depth; beyond Google’s own limit, paging deeper returns nothing new.

### Why is the snippet empty on some results?

Google renders no description for some results. The field comes back as an empty string rather than being absent, so test for empty rather than for missing.

### Can I use Google search operators like site: or inurl:?

Yes, by building the Google search URL yourself and pasting it into startUrls. searchTerms sends a plain query, so operators and tbs filters survive only through a URL.

### Can I check rankings in another country?

Yes. countryCode covers 240 countries and switches the Google domain as well as the region, es searches google.es. One run represents one market, so run a market per country.

### Can I get mobile search results?

Yes. Switch mobileResults on and the run returns the mobile SERP layout instead of desktop. Rankings routinely differ between the two, so track the device you care about.

### Can I target a city or postcode?

No. Targeting is country-level, through countryCode. There is no city, postcode or coordinate input, so local-pack and near-me work is outside what this scraper does.

### How much does it cost to track 1,000 keywords?

Checking 1,000 keywords to depth ten costs $2.00, one query each at $0.002, with the first ten results included. Daily for a month is $60.00.

### How does the price compare with Google’s Custom Search JSON API?

Google charges $5 per 1,000 queries and caps at 10,000 a day; this is $2 per 1,000 with no cap. Google’s API is also closed to new customers, with existing ones given until 1 January 2027 to move off it.

### Is there a free Google Search Scraper plan?

Yes. The free Apify plan runs it in demo mode: 5 runs a month, 10 items per run, no credit card.

### Does it need a Google API key or a proxy?

Neither. There is no API key, no Google Cloud project, no Programmable Search Engine to configure and no proxy pool to rent. An Apify account is the only requirement.

### Can AI agents call Google Search Scraper?

Yes. It runs in Claude, Cursor and other MCP clients through the Apify MCP server, and in n8n, Make and Zapier through the Apify app.

## Other Apidojo scrapers

Google Search is one of six sources in the catalogue. Every scraper publishes its inputs, its output fields and its price the same way this one does.

-   [YouTube Scraper Videos, channels, transcripts](/scrapers/youtube-scraper/)
-   [TikTok Scraper Videos, sounds, comments](/scrapers/tiktok-scraper/)
-   [Instagram Scraper Posts, reels, profiles](/scrapers/instagram-scraper/)
-   [Twitter Scraper Tweets, users, replies](/scrapers/twitter-scraper/)

[Browse all 26 scrapers](/scrapers/)

Apidojo

## Check your first keyword

One keyword, one country, ten results, $0.002, and free on the Apify demo plan. The output shape is the one documented on this page, and rank is the order it comes back in.

[Check your first keyword](https://apify.com/apidojo/google-search-scraper)

-   `searchTerms: ["your best keyword"] · us · 1 page` A top-ten check, for a fifth of a cent
-   `the same term × us, gb, de, tr` Four markets, four rankings, $0.008
-   `startUrls: ["google.com/search?q=site:yourdomain.com"]` What Google will actually show of your site

All three run on Google Search Scraper at $0.002 a query.

Apidojo is not affiliated with Google LLC.
