Migrate from SerpApi
Map SerpApi parameters and response fields to SerpHubAPI and switch over with a few lines of code.
SerpHubAPI uses the parameter names you already know (q, gl, hl, num), so most SerpApi integrations move over by changing the URL, the auth header and a few field names.
Quick switch
Before (SerpApi):
import requests
r = requests.get("https://serpapi.com/search", params={
"engine": "google",
"q": "coffee",
"gl": "us",
"hl": "en",
"num": 10,
"api_key": SERPAPI_KEY,
})
for item in r.json().get("organic_results", []):
print(item["position"], item["title"], item["link"])
After (SerpHubAPI):
import requests
r = requests.post("https://api.serphubapi.com/v1/search",
headers={"X-API-Key": SERPHUBAPI_KEY}, # shapi_xxxxxxxx
json={
"engine": "google",
"q": "coffee",
"gl": "us",
"hl": "en",
"num": 10,
})
for item in r.json()["results"].get("organic", []):
print(item["position"], item["title"], item["link"])
Parameter mapping
| SerpApi | SerpHubAPI | Notes |
|---|---|---|
GET https://serpapi.com/search | POST https://api.serphubapi.com/v1/search | JSON body instead of query string |
api_key (query) | X-API-Key header (or Authorization: Bearer) | Keys never go in the URL |
q | q | Same. For Yandex, SerpApi uses text; we use q for every engine |
engine=google | engine=google, type=web | |
engine=bing / engine=yandex | engine=bing / engine=yandex | Web results |
engine=google_news or tbm=nws | engine=google, type=news | |
engine=google_images or tbm=isch | engine=google, type=images | |
engine=google_videos or tbm=vid | engine=google, type=videos | |
engine=google_shopping or tbm=shop | engine=google, type=shopping | |
engine=google_maps | engine=google, type=maps | Results in results.places |
engine=google_scholar | engine=google, type=scholar | |
engine=google_autocomplete | engine=google, type=autocomplete | Results in results.suggestions |
gl | gl | Same |
hl | hl | Same |
num | num | 1–100 |
start (offset) | page (1-based) | page = start / num + 1 |
tbs=qdr:d / qdr:w / qdr:m / qdr:y | time_range=day / week / month / year | Other tbs values have no equivalent |
no_cache=true | mode=live (default) | |
| default (cached results allowed) | mode=cache_first | Half price; free on a cache hit |
output=html | — | Use format=markdown for a text rendering |
location, uule, google_domain, device | — | Not supported; use gl / hl |
GET /searches/{id}.json | GET /v1/searches/{id} | Archive kept 30 days |
GET /account.json | GET /v1/account |
Response mapping
| SerpApi | SerpHubAPI |
|---|---|
search_metadata.id | meta.id |
search_metadata.status | meta.status |
search_parameters | params |
organic_results | results.organic |
news_results | results.news |
images_results | results.images (original → image) |
video_results | results.videos |
shopping_results | results.shopping (source → merchant) |
local_results | results.places (title → name) |
related_questions | results.people_also_ask |
related_searches[].query | results.related_searches[] (plain strings) |
knowledge_graph | results.knowledge_graph |
error (string) | error.code + error.message |
Structural differences
| SerpApi | SerpHubAPI | |
|---|---|---|
| Request | GET with query string | POST with JSON body |
| Auth | api_key query parameter | X-API-Key or Authorization: Bearer header |
| Engine selection | One engine value per engine and vertical | engine + type; engine=auto lets us choose and fail over |
| Response shape | Differs per engine | One unified structure for every engine |
| Cost per call | Not in the response | meta.credits_charged on every response |
| Billing | Monthly subscription | Prepaid credits; paid balance never expires; empty results free |
| Page content | Not part of the search call | include_content on search, or /v1/fetch |
| Output formats | JSON or HTML | JSON or Markdown (format=markdown) |
| Errors | error string | {"error": {"code", "message"}} with stable codes |
Checklist
- Create a key at /dashboard/keys.
- Switch to
POST+ JSON +X-API-Key. - Replace
engine=google_*/tbmwithtype. - Replace
startwithpage. - Rename response fields (
organic_results→results.organic, etc.). - Handle errors by
error.code— see Errors. - Compare a few results side by side, then flip traffic.