serpgrab

Blog · October 20, 2026 · 4 min read

Migrating from SerpApi in two lines

serpgrab answers the same requests as SerpApi with the same JSON, so moving over is mostly a find-and-replace. This post shows the change for the three ways people usually call SerpApi, and lists what to check before you switch production traffic.

You will need a serpgrab key. The free one takes an email address at serpgrab.com and covers 250 searches a month.

Plain HTTP: change the host and the key

If you build the URL yourself (curl, fetch, requests, an HTTP node in a no-code tool), the two lines that change are the host and the key. The path, the parameter names and api_key stay as they are:

- https://serpapi.com/search.json?engine=google&q=coffee&location=Austin,Texas,United+States&api_key=SERPAPI_KEY
+ https://api.serpgrab.com/search.json?engine=google&q=coffee&location=Austin,Texas,United+States&api_key=SERPGRAB_KEY

If you would rather keep the key out of URLs and logs, send it as an X-API-Key header or as Authorization: Bearer <key> instead.

Google Maps works the same way: engine=google_maps with q and ll, on the same /search.json path.

Python: the official serpapi client

SerpApi’s own Python package keeps its host in one attribute, so you can point a client at serpgrab and leave the rest of your code alone:

import os
import serpapi

client = serpapi.Client(api_key=os.environ["SERPGRAB_KEY"], timeout=100)
client.BASE_DOMAIN = "https://api.serpgrab.com"  # the one new line

results = client.search(engine="google", q="coffee", location="Austin,Texas,United States")
for r in results["organic_results"]:
    print(r["position"], r["title"], r["link"])

Paging works too. next_page() and yield_pages() follow serpapi_pagination.next, and serpgrab fills that link with its own host:

for page in results.yield_pages(max_pages=3):
    for r in page.get("organic_results", []):
        print(r["title"])

We tested this with serpapi 1.1.2.

Node: swap getJson for fetch

SerpApi’s Node package (serpapi on npm) fixes its host name inside the library, so you can’t point it somewhere else. The good news is that getJson does very little, and a dozen lines of fetch (built into Node 18 and later) replace it with the same signature:

// before: import { getJson } from 'serpapi';
async function getJson(params) {
  const url = new URL('https://api.serpgrab.com/search.json');
  url.search = new URLSearchParams({ ...params, api_key: process.env.SERPGRAB_KEY });
  const res = await fetch(url, { signal: AbortSignal.timeout(100_000) });
  const data = await res.json();
  if (!res.ok) throw new Error(data.error ?? `serpgrab: HTTP ${res.status}`);
  return data;
}

const data = await getJson({ engine: 'google', q: 'coffee', location: 'Austin,Texas,United States' });
for (const r of data.organic_results ?? []) console.log(r.position, r.title, r.link);

Your existing getJson({...}) calls don’t change, as long as you pass them the parameters as an object.

On the Pro plan (RapidAPI)

Pro is billed through RapidAPI, so paid calls go to RapidAPI’s host, and the key travels in two headers instead of api_key. Everything else, including paths, parameters and responses, is the same:

curl -G 'https://google-serp-search-results-json.p.rapidapi.com/search.json' \
  --data-urlencode 'q=coffee' \
  --data-urlencode 'location=Austin,Texas,United States' \
  -H 'x-rapidapi-host: google-serp-search-results-json.p.rapidapi.com' \
  -H 'x-rapidapi-key: YOUR_RAPIDAPI_KEY'

With the Python client, set the host and add the headers to its session:

client = serpapi.Client(timeout=100)
client.BASE_DOMAIN = "https://google-serp-search-results-json.p.rapidapi.com"
client.session.headers.update({
    "x-rapidapi-host": "google-serp-search-results-json.p.rapidapi.com",
    "x-rapidapi-key": os.environ["RAPIDAPI_KEY"],
})

In the Node helper, change the URL to the same host and pass those two headers to fetch.

Set a longer timeout

Most searches answer in 1-5 seconds. Now and then a search needs a fresh connection to Google and takes up to about 70 seconds, which is longer than the Node library’s 60-second default. The examples above use 100 seconds. Whatever client you use, give it at least that.

What stays the same

What to check before you switch

These are the gaps, so you find them now rather than in production:

If your code reads any of those, keep that part on SerpApi for now, or email us and tell us which one you need.

A safe way to switch

  1. Run your usual queries against both APIs for a day and compare the blocks your code reads. Expect some values to differ, because Google reshuffles results from minute to minute and the two searches won’t see the exact same page.
  2. Move a slice of traffic, watch your error rate, then move the rest.
  3. Keep the SerpApi key until the first month has gone by without surprises.

Try it

Get a free key at serpgrab.com: 250 searches a month, no card. After that, Pro is $15 for 5,000 searches a month on RapidAPI, against $75 on SerpApi’s Developer plan (how we compare with SerpApi, SearchApi and Serper). If something your code relies on doesn’t match SerpApi, email hello@serpgrab.com and we will look at it.

Get 250 free searches