Skip to main content
SERP Maven

SERP Maven

Self-hosted SERP API alternative: search results from a real Chrome browser and your own residential proxy.

pip install serpmaven. Formerly gserp and google-browser-scraper: both now install serpmaven, and their old commands, imports and GSERP_* / GBS_* variables keep working.

pypi python tests license docker 2 GB free with code GOOGLENM

SERP Maven on DevHunt

Quickstart · Output · Poisoned results · HTTP API · MCP · Docker · How it works · Options


A real Chrome window showing Google results next to the JSON the scraper produced for them

✅ 100% 📉 0.4 MB ⚡ 1.4 s
success rate per search per search on a warm proxy IP

Latest version benchmarks (v0.1)

Scrape Google search results (SERP) with a real Chrome browser and your own residential proxy, and get clean JSON back. Use it as a CLI, a Python library, a local HTTP API, or an MCP server that gives AI agents live Google search.

Plain HTTP is no longer a reliable way to scrape Google, and a fresh browser on a fresh proxy IP is refused quickly. So the scraper warms its first sticky proxy session with ordinary browsing and starts later ones from the cookies Google already accepts, lets the browser pass Google's checks, and then fetches results pages directly over HTTPS with the browser's own cookies. Captchas and blocks are reported as such, never as "no results".

Features

⚡ Hybrid mode
Results pages over HTTPS between Google's checks: a fraction of a browser's traffic and time. The browser takes over by itself when needed.

🛡️ Poisoned results protection
Pages of results for some other query are caught: the proxy IP serving them is dropped within a few pages and the query is asked again on a fresh one.

🌐 Real browser
Real Chrome via Patchright, warmed up once and then carrying the cookies Google already trusts to every new identity, so Google's checks pass.

🧩 SERP API-style JSON
organic_results, ads, related_questions, related_searches, pagination, ai_overview, local_results.

🔌 Bring your own proxy
Any residential proxy with sticky sessions, built-in NodeMaven support.

🚦 Honest failures
Captchas and blocks come back labeled, not as empty results.

🤖 For AI agents
An MCP server that gives agents live Google search, with the AI Overview and map places.

🐳 Run it your way
CLI, Python library, HTTP API, MCP server or Docker image. Traffic and cost per 1000 pages in every run summary.

Use cases

  • SEO rank tracking and SERP monitoring for your own keywords
  • Keyword and competitor research from live Google results
  • Web search for AI agents and LLM apps through MCP
  • A self-hosted alternative to paid Google search APIs when you already pay for proxies

Install

Python 3.10 or newer, in a virtual environment:

python3 -m venv serpmaven-env
source serpmaven-env/bin/activate
pip install serpmaven
patchright install chromium
serpmaven doctor

In PowerShell:

python -m venv serpmaven-env
Set-ExecutionPolicy -Scope Process Bypass -Force   # lets this window run Activate.ps1
.\serpmaven-env\Scripts\Activate.ps1
pip install serpmaven
patchright install chromium
serpmaven doctor

doctor ends with ready when the browser starts and looks like a desktop.

On a Linux server (no screen)

The browser runs with a window, so a server needs a virtual display, and software WebGL when there is no GPU:

sudo apt install xvfb
sudo serpmaven-env/bin/patchright install-deps chromium
export SERPMAVEN_BROWSER_ARGS=--enable-unsafe-swiftshader
xvfb-run -a serpmaven doctor

Then start every command with xvfb-run -a. The Docker image has all of this built in.

Quickstart

serpmaven search "best running shoes" --proxy "http://USER-session-{session}:PASS@gate.example.com:7000" -o results.jsonl

The first query takes a few minutes while the first proxy IP warms up on a few ordinary pages; the terminal shows each step. Later queries take seconds, and new proxy IPs start from its cookies. Every run ends with the pages served and the traffic used, warm-up apart from the pages.

With NodeMaven

The session id is handled for you and the credentials come from the environment:

pip install "serpmaven[nodemaven]"
export NODEMAVEN_LOGIN=... NODEMAVEN_PASSWORD=...
printf "best running shoes\nhow to boil eggs\n" > queries.txt
serpmaven search -f queries.txt --nodemaven --country us -o results.jsonl

In PowerShell:

pip install "serpmaven[nodemaven]"
$env:NODEMAVEN_LOGIN = "..."; $env:NODEMAVEN_PASSWORD = "..."
Set-Content queries.txt "best running shoes", "how to boil eggs"
serpmaven search -f queries.txt --nodemaven --country us -o results.jsonl
Cap a run's traffic with a demo sub-user

--nodemaven-demo creates a sub-user with a traffic limit from your dashboard API key, shares it across workers, and deletes it when the run ends (--keep-subuser keeps it). The account needs sub-users enabled. A fresh warm-up alone uses about 60 MB, so keep the cap well above that:

export NODEMAVEN_API_KEY=...
serpmaven search -f queries.txt --nodemaven-demo --traffic-limit-mb 300 -o results.jsonl
Try it without a proxy
serpmaven search "best running shoes" --no-proxy

Google then sees one address for every query, so it starts answering with captchas sooner than it would across a pool of proxy IPs. Those pages come back as captcha in page_verdict, not as empty results.

From Python

from serpmaven import ProxyTemplate, Scraper, Settings

proxy = ProxyTemplate("http://USER-session-{session}:PASS@gate.example.com:7000")
for page in Scraper(proxy, Settings(pages=2)).run(["best running shoes"]):
    for result in page.get("organic_results", []):
        print(result["position"], result["title"], result["link"])

What you get

One JSON object per results page:

{
  "search_metadata": {"status": "Success", "page_verdict": "ok", "fetched_with": "http"},
  "search_parameters": {"engine": "google", "q": "best running shoes", "page": 1},
  "organic_results": [
    {"position": 1, "title": "...", "link": "https://...", "snippet": "..."}
  ],
  "related_questions": [{"question": "..."}],
  "ai_overview": {"text": "..."},
  "exit": {"session": "...", "queries_on_exit": 1, "bytes": "..."}
}

The field names are the ones common to SERP APIs, so simple consumers can often switch with minimal mapping.

All fields
  • organic_results, ads, related_questions, related_searches, pagination, search_metadata
  • ai_overview: the text of Google's AI Overview when the page shows one (pages in English, --hl en, the default)
  • local_results: the places of the map pack on local queries (name, rating, reviews, type, address, phone, opening hours)
  • exit: which proxy IP (sticky session) answered and how many bytes the page cost
  • search_metadata.fetched_with: http or browser
  • search_metadata.timings: seconds per step (http for a page fetched over HTTP; type, load, ready and read for one the browser rendered; parse; links, which overlaps the next query)
  • A query that failed is a record too, with an error

Knowledge panels, shopping, images and other special blocks are not parsed. --format csv writes the organic results as a table, and --price-per-gb adds the cost per 1000 pages to the summary.

Poisoned results protection

Google does not always block a scraper. Sometimes it answers with a normal-looking results page for a different query: no captcha, no error, just wrong data that slips into your pipeline unnoticed.

The scraper checks results pages against the queries it asked. When a proxy IP starts returning unrelated results, it is dropped within a few pages and the query is asked again on a fresh one.

  • No extra requests, no extra traffic: the check runs on the page already downloaded
  • On by default

Run it as an API

serpmaven serve --nodemaven --country us --prewarm
curl "http://127.0.0.1:8000/search.json?q=best+running+shoes"

In PowerShell, call curl.exe (plain curl there is another command).

  • Same record format as above
  • hl (language) and gl (country) per request: /search.json?q=...&hl=de&gl=at
  • --prewarm finds a proxy IP Google serves at startup, so the first request does not wait for a warm-up; /health answers 503 warming until then
  • Results pages are read one at a time on one held proxy IP; a page's links resolve in the background, so the next request starts while the last one waits for its links
  • links=N resolves the links of the first N organic results only (0: none)
  • links_wait=S answers after S seconds with the links resolved by then; links still being resolved are null and counted in search_metadata.links_pending
  • async=true answers at once with search_metadata.id; GET /searches/<id>.json answers "status": "Processing" until the search and its links are done, then the record. The newest 500 searches are kept there, each for up to an hour; up to 50 async searches wait for the browser at once, more are answered 429
  • Set SERPMAVEN_API_KEY to require a key; without one the server only listens on localhost

Use it from an AI agent (MCP)

{
  "mcpServers": {
    "google-search": {
      "command": "serpmaven",
      "args": ["mcp", "--nodemaven", "--country", "us", "--prewarm"],
      "env": {"NODEMAVEN_LOGIN": "...", "NODEMAVEN_PASSWORD": "..."}
    }
  }
}

One tool, google_search(query, pages, hl, gl). It returns the organic results, "People also ask", related searches, and the AI Overview and map places when Google shows them.

Docker

A ready image is published to GitHub Container Registry with every release:

docker run --rm ghcr.io/nodemaven/serpmaven doctor
docker run --rm -p 8000:8000 -e SERPMAVEN_API_KEY=change-me \
  -e SERPMAVEN_PROXY='http://USER-session-{session}:PASS@gate.example.com:7000' \
  ghcr.io/nodemaven/serpmaven serve --host 0.0.0.0

To build it yourself: docker build -t serpmaven .

How it works

  1. New identity: a sticky proxy session and a fresh browser profile.
  2. Warm-up: the first proxy IP opens a few ordinary pages, staying on each for 20-45 seconds. Later ones start from the Google cookies of a served proxy IP and are warmed up only when no such set is accepted.
  3. Search: the first query on a proxy IP goes through the browser. Once Google serves it, the next pages come over HTTPS with the browser's cookies, until Google asks for its check again.
  4. Check before parsing: a captcha or a block is reported as one, never parsed as an empty result.
  5. Keep or drop: a proxy IP Google answers is reused; one it refuses is dropped and the query retried on a new one. If one proxy IP after another is refused, the run stops instead of spending more traffic.
More detail: HTTP between checks, holding proxy IPs, copied cookies, result links, traffic

HTTP between checks. After the browser passes Google's check, results pages are fetched over HTTPS with the browser's own headers and cookies. If that stops working, the scraper goes back to the browser on its own. --no-hybrid uses the browser for every page.

Unrelated results. A proxy IP that starts returning results unrelated to the queries is dropped, and the query is asked again on a new one.

Holding proxy IPs. A served proxy IP is kept for up to 300 queries. Every new one pays for a browser check, and for a warm-up when no cookie set is accepted, so a short cap mostly buys more of that traffic. Every 50 results pages it renders, the browser is restarted on the same profile and proxy IP, which keeps its memory from growing over a long hold. A browser error on a search is retried once on the same proxy IP before it is dropped; a network error, running out of memory or a crashed browser drops it at once.

Copying cookies. With --renew-cookies 0, the command line copies the cookies of the first proxy IP Google serves and starts new proxy IPs from that copy, on new sticky sessions, instead of warming each one; all workers share the copy. Google's acceptance follows the cookies more than the address, so a copy usually starts out served and costs a few MB instead of a full warm-up. A copy waits 40-60 seconds after its browser starts before the first search.

Copying the cache. Pages get cheaper as a proxy IP is held, because the browser cache fills with Google's shared scripts and images. Copies carry that cache too, so a new proxy IP starts with cheap pages, and the copy is refreshed from the held one at each browser restart, when its cache is warm. If two copies carrying the cache are refused on their first search, the rest of the run copies cookies only (--no-clone-cache does that from the start).

Starting from saved cookies. --cookies FILE gives every new proxy IP the Google cookies of a browser Google already serves, so it skips the warm-up; the file can come from another machine. --renew-cookies N replaces that set with the cookies of a served proxy IP every N queries, so it stays fresh, and without --cookies it ends the warm-ups after the first renewal. It is on by default, every 25 queries, so a run warms up its first proxy IP and rarely another; --renew-cookies 0 goes back to copies of the first served profile. --cookies-out DIR saves each renewed set for the next run, readable by its owner only. If every set is refused in turn, new proxy IPs are warmed up again, and with --renew-cookies the next renewal brings the sets back. A file is a JSON list of Playwright cookie records, or an object with that list under "cookies", and must hold Google's NID cookie.

Result links. Google wraps result links in encrypted /goto redirects. Each one is resolved with a small request on the proxy IP the page came from, with that page's cookies, in the background while the next query runs; a link left over is tried through a separate short-lived proxy session. Google answers only a few links of a page at once and holds the rest on a "Verifying your request" page; a link held for up to 30 seconds is asked again when the wait is over, twice at most and within 45 seconds a page, so a page's links can take up to 45 seconds while the queries carry on. Records still come out in the order each browser searched them.

Traffic. Everything goes through a small local relay that counts bytes per host and refuses what no search needs: the models and data files Chrome otherwise downloads into every fresh profile, and the videos of a warm-up page.

The defaults come from measurements in proxy-benchmark.

Options

All search options
Option Default What it does
--workers N 1 Search on N proxy IPs at once, one browser each, from one list of queries
--max-per-exit N 300 Queries before a served proxy IP is retired
--restart-every N 50 Results pages the browser rendered before it restarts on the same profile and proxy IP; 0 never
--no-hybrid Fetch every results page in the browser instead of over HTTP between Google's checks
--hl, --gl en, unset Language and country of the results
--clone N 10 With --renew-cookies 0: new proxy IPs started from copied cookies; 0 turns copying off
--clone-max-age 180 Minutes copied cookies stay in use
--clone-refusals N 1 Copies refused in a row on their first query that end the copying
--no-clone-cache Copies carry cookies only, not the browser cache
--cookies FILE Start every new proxy IP from the Google cookies in FILE instead of a warm-up; repeat for more files, the next one taking over after two proxy IPs in a row are refused on their first query, and warm-ups again once every file has been refused that way. Turns --clone off
--renew-cookies N 25 Every N served queries, a proxy IP's Google cookies become the set new proxy IPs start from; 0 turns it off and brings back --clone
--cookies-out DIR Write each renewed cookie set to DIR, for the next run's --cookies
--warmup L3 Pages a fresh proxy IP opens before its first query: L3, light (without Google Trends: much less traffic, served on the first query less often), L2, L1, off
--spare N 0 Proxy IPs warmed in the background so a retired one is replaced at once; each costs a warm-up
--direct all Open results pages directly: all, follow-ups (all but the first query on each proxy IP), none
--input type How a query goes into the search box: type, insert, words
--gap LOW,HIGH 2,5 Seconds between queries on one proxy IP
--pages N 1 Result pages per query
--format jsonl jsonl or csv
--price-per-gb Your proxy price, to print the cost per 1000 pages
--no-resolve-links Keep result links as Google /goto redirects
--save-html DIR Keep every page's HTML, gzipped

-v prints every step as JSON instead, and the summary as one JSON line. serpmaven search --help lists the rest.

Proxies

Any provider with sticky sessions works through --proxy and a {session} placeholder. A proxy without one is accepted with a warning: if the proxy IP changes on every request, warming it does nothing. SOCKS5 needs an IP-whitelisted endpoint, because Chrome cannot send a SOCKS5 username and password.

Check your machine

serpmaven doctor

Starts the browser on a blank page, sends nothing, and reports what a website would see: whether the browser looks headless, whether WebGL works, the screen size. Google answers some machines much less than others, so run this first.

What this is not

Not a free Google Search API, and not a guarantee that every proxy IP will work. It is a browser-based collector that makes failures explicit, drops proxy IPs Google refuses, and tells you what each page cost.

Status

Early. The cloak engine (--engine cloak) is experimental; patchright is the default.

Google changes its pages often. If results come back empty or wrong, run with --save-html DIR and open an issue with what you see.

You are responsible for using this within Google's terms and the law where you run it.

Adding an engine

An engine joins this tool only after it has been measured on proxy-benchmark. Add it there and run the warm-up ladder against Google:

python scripts/run_ladder.py --engines your-engine

Then open a pull request here with the run file. The ladder runs identities with and without the warm-up in the same hours, so the result shows whether the engine actually gets served, not whether it got lucky once.

License

MIT

Metadata

Release files for serpmaven 0.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for serpmaven 0.2.2
File Size Uploaded Provenance Actions
serpmaven-0.2.2.tar.gz 154.0 kB With provenance Details for serpmaven-0.2.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for serpmaven 0.2.2
File Interpreter ABI Platform Actions
serpmaven-0.2.2-py3-none-any.whl Python 3 none any Details for serpmaven-0.2.2-py3-none-any.whl

Total release size: 252.6 kB

Release files / serpmaven-0.2.2.tar.gz

Download URL serpmaven-0.2.2.tar.gz
Size 154.0 kB
Tags Source
SHA-256 checksum
How to use checksums
28ab47e8095c8fe6433c8a6bb3fe8c51cdb071ed1f6008e557c17eac9a66b14e
BLAKE2b-256 checksum
How to use checksums
bc76dac6f81c7adb0ed2e0090db1b8ab0126a6c65fd5344e144b84a2d2efd05c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

Release files / serpmaven-0.2.2-py3-none-any.whl

Download URL serpmaven-0.2.2-py3-none-any.whl
Size 98.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ea1edeb0e443a438756e329b40952cb3d817fbcfc00cab90b2a3de8f9cb53ed1
BLAKE2b-256 checksum
How to use checksums
109aa04fad53a6a1a281e026accac17991f5ed6d4eda932fdd96ed69dd735bfe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

Security for serpmaven 0.2.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for serpmaven-0.2.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.2 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page