> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hasdata.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Google Search Results Scraper

Track SERP rankings, monitor competitors, research keywords, and audit SEO presence at scale. Returns position, keyword, title, link, displayedLink, snippet, highlighted words, source, rich snippet blocks, and sitelinks for every query × location combination.

This scraper job is asynchronous. You'll receive a `jobId`, and can fetch results via polling or webhook delivery.

## Request Cost

Each row of data returned consumes **2 credits** from your balance.

<Tip>Credits are deducted only for successful rows.</Tip>

## Example Request

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://api.hasdata.com/scrapers/google-serp/jobs' \
    --header 'Content-Type: application/json' \
    --header 'x-api-key: <your-api-key>' \
    --data '{"keywords":["pizza in new york","beef in new york"],"location":"Austin,Texas,United States","limit":0}'
  ```

  ```javascript Node.js theme={null}
  const axios = require('axios').default;

  const options = {
    method: 'POST',
    url: 'https://api.hasdata.com/scrapers/google-serp/jobs',
    headers: {'Content-Type': 'application/json', 'x-api-key': '<your-api-key>'},
    data: {
      keywords: ['pizza in new york', 'beef in new york'],
      location: 'Austin,Texas,United States',
      limit: 0
    }
  };

  try {
    const { data } = await axios.request(options);
    console.log(data);
  } catch (error) {
    console.error(error);
  }
  ```

  ```python Python theme={null}
  import requests

  url = "https://api.hasdata.com/scrapers/google-serp/jobs"

  payload = {
      "keywords": ["pizza in new york", "beef in new york"],
      "location": "Austin,Texas,United States",
      "limit": 0
  }
  headers = {
      "Content-Type": "application/json",
      "x-api-key": "<your-api-key>"
  }

  response = requests.post(url, json=payload, headers=headers)

  print(response.json())
  ```

  ```php PHP theme={null}
  <?php

  $payload = [
      "keywords" => ["pizza in new york", "beef in new york"],
      "location" => "Austin,Texas,United States",
      "limit" => 0,
  ];

  $curl = curl_init();

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.hasdata.com/scrapers/google-serp/jobs",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => json_encode($payload),
    CURLOPT_HTTPHEADER => [
      "Content-Type: application/json",
      "x-api-key: <your-api-key>",
    ],
  ]);

  $response = curl_exec($curl);
  curl_close($curl);

  echo $response;
  ```

  ```java Java theme={null}
  OkHttpClient client = new OkHttpClient();

  MediaType mediaType = MediaType.parse("application/json");
  String json = """
    {
      "keywords": [
        "pizza in new york",
        "beef in new york"
      ],
      "location": "Austin,Texas,United States",
      "limit": 0
    }
  """;
  RequestBody requestBody = RequestBody.create(json, mediaType);

  Request request = new Request.Builder()
    .url("https://api.hasdata.com/scrapers/google-serp/jobs")
    .post(requestBody)
    .addHeader("Content-Type", "application/json")
    .addHeader("x-api-key", "<your-api-key>")
    .build();

  Response response = client.newCall(request).execute();
  ```

  ```csharp C# theme={null}
  using System.Net.Http;
  using System.Text;

  var client = new HttpClient();

  var json = """
  {
    "keywords": [
      "pizza in new york",
      "beef in new york"
    ],
    "location": "Austin,Texas,United States",
    "limit": 0
  }
  """;
  var content = new StringContent(json, Encoding.UTF8, "application/json");

  var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api.hasdata.com/scrapers/google-serp/jobs")
  {
      Content = content,
  };
  request.Headers.Add("x-api-key", "<your-api-key>");

  using var response = await client.SendAsync(request);
  response.EnsureSuccessStatusCode();
  var body = await response.Content.ReadAsStringAsync();
  Console.WriteLine(body);
  ```

  ```ruby Ruby theme={null}
  require 'net/http'
  require 'uri'
  require 'json'

  uri = URI("https://api.hasdata.com/scrapers/google-serp/jobs")
  payload = {
    "keywords" => ["pizza in new york", "beef in new york"],
    "location" => "Austin,Texas,United States",
    "limit" => 0,
  }

  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true

  request = Net::HTTP::Post.new(uri)
  request["Content-Type"] = 'application/json'
  request["x-api-key"] = '<your-api-key>'
  request.body = payload.to_json

  response = http.request(request)
  puts response.read_body
  ```

  ```rust Rust theme={null}
  use reqwest::blocking::Client;
  use serde_json::json;

  fn main() -> Result<(), Box<dyn std::error::Error>> {
      let client = Client::new();
      let payload = json!({
          "keywords": [
              "pizza in new york",
              "beef in new york"
          ],
          "location": "Austin,Texas,United States",
          "limit": 0
      });
      let res = client
          .post("https://api.hasdata.com/scrapers/google-serp/jobs")
          .header("Content-Type", "application/json")
          .header("x-api-key", "<your-api-key>")
          .json(&payload)
          .send()?
          .text()?;
      println!("{}", res);
      Ok(())
  }
  ```

  ```go Go theme={null}
  package main

  import (
  	"bytes"
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	payload := []byte(`{
    "keywords": [
      "pizza in new york",
      "beef in new york"
    ],
    "location": "Austin,Texas,United States",
    "limit": 0
  }`)

  	req, _ := http.NewRequest("POST", "https://api.hasdata.com/scrapers/google-serp/jobs", bytes.NewBuffer(payload))
  	req.Header.Add("Content-Type", "application/json")
  	req.Header.Add("x-api-key", "<your-api-key>")

  	res, _ := http.DefaultClient.Do(req)
  	defer res.Body.Close()

  	responseBody, _ := io.ReadAll(res.Body)
  	fmt.Println(string(responseBody))
  }
  ```
</CodeGroup>

## Job Parameters

<ParamField body="keywords" type="string[]" required>
  Put each keyword on the different line
</ParamField>

<ParamField body="location" type="string" required>
  Google canonical location for the search.
</ParamField>

<ParamField body="limit" type="number">
  Results per each keyword (min. 10). The default value of 0 means no limit.
</ParamField>

## Supported Enrichments

Request any of the fields below via the `enrichments` array in your job payload.

| ID        | Title           | Description                      | Cost per Request |
| --------- | --------------- | -------------------------------- | ---------------- |
| `email`   | Email Address   | Website-associated email address | 5 credits        |
| `phone`   | Phone Number    | Website-associated phone number  | 5 credits        |
| `revenue` | Revenue         | Company revenue                  | 5 credits        |
| `traffic` | Website Traffic | Website traffic                  | 5 credits        |

## Getting Results

<Card title="Webhooks" horizontal icon="webhook" href="/scrapers/webhooks">
  Receive real-time updates when your scraper job starts, completes, or collects data.
</Card>

<Card title="Results API" horizontal icon="list" href="/scrapers/getting-results">
  Use the Results API to fetch your data using the `jobId`, with support for polling and pagination.
</Card>

<Card title="Stopping a Job" horizontal icon="circle-stop" href="/scrapers/stopping-job">
  Cancel an active scraper job early if it's no longer needed or you want to save credits.
</Card>
