Google results (SERP)

GEThttps://api.crawl4ai.com/serp

Google's results page as structured data: true ranks, every block Google showed, and the place the page was localised to. Built for rank tracking and SEO tools. Not the same as /search, which is Crawl4AI's own web search for reading results. In beta since 8 October 2026: the shape is settled, the service is new; it becomes stable in a few weeks. POST /serp takes the same fields as a JSON body.

512 chars the longest query1 credit per Google page fetched live
Status

beta · added 8 Oct 2026

Request

curl "https://api.crawl4ai.com/serp?q=best+crm+software&country=us" \
  -H "Authorization: Bearer sk_live_..."

Query

qrequired
string

The search query (max 512 chars).

country
string
Default us

Default us. Two letters: the country Google serves the page for.

language
string
Default en

Default en. The language of Google's page.

location
string

Optional. A city or region, for example Austin, TX. The answer's search.location shows the full name we used (Austin,Texas,United States). An unknown name answers 400 with the closest names in closest.

num
10, 20, 30 … 100
Default 10

Default 10, any multiple of 10. Results per page: num=30 fetches Google pages 1 to 3 at the same time and returns every organic result on them.

page
int
Default 1

Default 1. Counts in steps of num: num=20&page=2 is Google pages 3 and 4. No request reaches past Google page 30.

device
string
Default desktop

Default desktop. desktop is the only value today.

time
string

Optional. hour, day, week, month or year: only results from that past period.

fresh
0 | 1
Default 0

Default 0. 1 skips the cache and fetches the page live, at the live price.

source
auto | google
Default auto

Default auto: a live Google result by either road (gg or gs in the answer's source). google: only gg, the road that also returns the AI Overview when Google shows one. When it cannot answer, the call ends with a 503, and a failed call costs nothing.

engine
string
Default google

Default google. google is the only value today.

type
string
Default organic

Default organic. organic is the only value today.

Response

Shortened, for q=car insurance quotes:

{
  "search": { "q": "car insurance quotes", "engine": "google", "type": "organic", "country": "us", "language": "en",
              "location": null, "device": "desktop", "page": 1, "num": 10, "time": null },
  "cached": false, "age_s": 0, "source": "gg",
  "pages": { "asked": 1, "got": 1, "missing": [] },
  "blocks": [ "ai_overview", "organic", "people_also_ask", "related_searches" ],
  "total_results": 238000000,
  "results": [
    { "position": 1, "position_absolute": 2, "title": "…", "url": "https://www.libertymutual.com/…",
      "domain": "libertymutual.com", "displayed_url": "https://www.libertymutual.com › auto-insurance › state",
      "snippet": "…" },
    …
  ],
  "ai_overview": { "text": "You can compare rates…", "sources": [ { "title": "The Zebra", "url": "https://…" } ] },
  "people_also_ask": [ "…", "…", "…", "…" ],
  "related_searches": [ "…" ],
  "ms": 1240
}

The top-level keys:

search
object

The settings the page was fetched with: q, engine, type, country, language, location, device, page, num, time.

results
array

The organic results, in Google's order (below). No results is a 200 with an empty list.

blocks
array

The names of the blocks that were on the page, in page order.

total_results
int

Google's own estimate, as printed on the page ("About 116 results"). With a place attached it is often a small number. Absent when Google did not show one.

source
gg | gs | mixed

Where the pages came from: gg and gs are both live Google results, mixed means some pages of each. A gs page has fewer blocks and no position_absolute, and blocks names only what it has.

empty_reason
string

Only when results is empty. google_no_results: Google's own "did not match any documents" page. rescue_no_results: Google refused the query to us and our fallback had nothing; another provider may still have results, so fall back on this one only.

cached
bool

true when every page came from our cache; age_s is then the age of the oldest page, in seconds. fresh=1 skips the cache.

pages
object

{asked, got, missing}: the number of Google pages asked for, the number we got, and the page numbers we could not get.

ms
int

The time the answer took, in milliseconds.

Each result:

position
int

The rank among the organic results only, from 1.

position_absolute
int

The rank among every block on the page, in page order: an ad, an AI Overview or a places block each take a number too.

title
string

The result's title.

url
string

The page itself, not a redirect.

domain
string

The host of url, lower case, without www..

displayed_url
string

The address Google prints under the title, with its › parts; empty when Google prints none.

snippet
string

The text Google shows, without the date at its start.

date
string

Optional. The date Google shows, as shown (Jul 20, 2026, 3 years ago).

sitelinks
array

Optional. The small links under the result: {title, url}.

The blocks

A block Google did not show is absent, never null. Each block's key and its item fields:

Key Fields
ai_overview {text, sources: [{title, url}]}
people_also_ask a list of questions (strings)
related_searches a list of searches (strings)
knowledge_panel {title, subtitle, description, facts: [{k, v}]}
top_stories [{title, url}]
local_pack [{position, name, rating, reviews_count, address}]
ads_top · ads_bottom [{position_absolute, title, url, displayed_url, snippet}]
short_videos [{title, url, source, duration}]
images [{title, url, source}]; url is the page the image is on
latest_from_site [{title, url, date}]; latest_from_site_domain names the site
perspectives [{title, url, source, author, date}]
apps [{title, url, store}]

blocks can also name videos and discussions: they were on the page and take a number in position_absolute, but they have no list of their own. A block can be named in blocks with no list when we could not read its links.

Depth and paging

For exact ranks past the first 10, ask a bigger num: its Google pages are fetched at the same time, and position runs on across them. With page above 1, numbers start at (page-1)×num+1; this is an estimate, because a Google page holds 8 to 10 organic results. If a later page fails, the answer is still a 200 with the pages we got, and pages.missing names the failed ones.

Credits and errors

1 credit per Google page fetched live; a page from our cache costs half. The x-c4-cost header carries the real cost of the call. A failed first page or a blocked fetch is a 5xx and is not charged. A bad setting answers 400 with the reason in error.

Try it with your key

Run this call in the playground and see the real answer, the time and the units.

Open the playground

Next

Something unclear or wrong on this page? Tell us.