I Self-Hosted SearXNG as a Free SERP API. Here's the Honest Verdict
Every "free SERP API" thread on Reddit eventually points at the same answer: just self-host SearXNG. It's open source, it queries Google and dozens of other engines, it has a JSON output, and it costs nothing but a container. On paper it's the obvious searxng serp api everyone recommends and nobody seems to have actually run at load.
So I ran it. I spun up SearXNG in Docker on July 22, 2026, turned on its JSON API, and hit it like an API — from a single normal IP, the way a small project would. It works, and I'd happily use it for private search. But as a drop-in Google SERP API it hit three walls in the first ten minutes, and the honest verdict is more "free to run, not free to operate" than "free API."
TL;DR: Self-hosting SearXNG as a SERP API is genuinely free and it does work — with caveats. Its JSON API is off by default (you edit settings.yml), a broken default engine 500s every query until you restrict engines, and from one IP most engines get CAPTCHA'd: Google returned zero parseable results, Brave and Startpage were suspended, and only DuckDuckGo answered reliably. Median latency was ~0.83s. Great for private search; for reliable Google JSON at volume you either add your own proxy pool or use a managed SERP API.
The setup: SearXNG in Docker
The install is the easy part and SearXNG deserves credit for it. One command brings up the whole stack:
# Run SearXNG; it writes a default settings.yml into ./searxng on first boot
docker run -d --name searxng \
-p 8899:8080 \
-v "$PWD/searxng:/etc/searxng" \
searxng/searxng:latest
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8899/ # 200
The web UI comes up, search works in the browser, and for a private, ad-free, self-hosted metasearch that's basically the finish line. But I wanted the searxng json api — the machine-readable endpoint you'd build on — and that's where the friction started.
Wall 1: the JSON API is off by default
Point anything at /search?q=test&format=json on a fresh install and you get a 403. SearXNG ships with only the HTML (and CSV/RSS) formats enabled; JSON is deliberately opt-in. You turn it on in settings.yml, and while you're there you also need a secret key and, for automated access, the rate limiter switched off:
# settings.yml (mounted at /etc/searxng/settings.yml)
use_default_settings: true
server:
secret_key: "change-me-to-something-long"
limiter: false # the bot limiter blocks programmatic calls
image_proxy: false
search:
formats:
- html
- json # this line is what unlocks the JSON API
Restart the container and format=json starts answering. Nothing hard here — but it's the first sign that SearXNG is a search app you operate, not an API someone runs for you. Every one of these knobs is now yours to own.
Wall 2: a broken engine 500s every query
With JSON enabled, my first real query returned a 500. Not a 429, not an empty result — a server error. The container logs told the story:
ERROR:searx.search.processors: can't register engine processor:
wikidata (init failed)
...
KeyError: 'wikidata'
Here's the chain. On startup, SearXNG health-checks each engine. The wikidata engine's init request came back 403 from that IP, so the engine never registered. But the default general-search query still references wikidata, so every unrestricted JSON query crashed looking up an engine that wasn't there. I confirmed it was deterministic: a plain /search?q=test&format=json reliably 500'd.
There's also a quieter requirement next to it. SearXNG's bot detection logs X-Forwarded-For nor X-Real-IP header is set and refuses to behave normally unless you send a proxy header. So the working request had two fixes: pin the engines to ones that actually initialized, and send X-Forwarded-For.
curl -s -H "X-Forwarded-For: 127.0.0.1" \
"http://localhost:8899/search?q=best+serp+api&format=json&engines=duckduckgo"
# HTTP 200 — 10 results
Restricting to engines=duckduckgo got me a clean 200 with 10 results. Good — but notice what just happened. To make a "Google-and-everything" metasearch stop crashing, I had to narrow it down to one engine that wasn't Google. That foreshadows the real problem.
Wall 3: most engines get CAPTCHA'd from one IP
This is the finding that decides whether SearXNG can be your SERP API. I asked for several engines at once and read the unresponsive_engines field SearXNG helpfully returns. From a single residential IP, here's what each engine actually did:
| Engine (via SearXNG) | Result from one IP (Jul 22 2026) |
|---|---|
| DuckDuckGo | OK — returned 10 results |
| Brave | Suspended — "too many requests" |
| Startpage | Suspended — "CAPTCHA" |
| 0 parseable results |
One engine out of four returned usable data, and it was DuckDuckGo. Brave and Startpage suspended themselves after tripping their own automated-overuse limits; Google returned a page SearXNG couldn't extract results from. That last one lines up with a broader change we've documented separately — Google now renders organic results with JavaScript, so a server-side scraper often gets a shell with nothing to parse.
The uncomfortable implication: out of the box, a self-hosted SearXNG behaves like a DuckDuckGo proxy, not a Google API. You can absolutely fix this — SearXNG lets you route engines through your own proxies, and with a residential pool the other engines come back to life. But now you're sourcing, rotating and paying for proxies, tuning per-engine settings, and babysitting the exact anti-bot fight a hosted API exists to absorb. The software is free; the operation is not. If you're weighing that trade, we put real numbers on it in the true cost of running your own Google scraper.
Latency and the field that lies
On the queries that worked, the SearXNG aggregation layer added roughly 0.74–0.89 seconds, a median near 0.83s across three queries. That's the cost of fanning out to multiple engines and waiting for the slowest to answer — fine for a human hitting the search box, slower than a purpose-built endpoint when you're pulling thousands of queries.
One trap to note if you build on the JSON: the number_of_results field is unreliable. It came back as 0 on responses that plainly contained 10 results in the results array. Count the array length yourself; don't trust that field for pagination or "did I get anything" checks.
{
"query": "best serp api",
"number_of_results": 0, // <-- lies; there are 10 below
"results": [ { "engine": "duckduckgo", "title": "...", "url": "..." }, ... ],
"unresponsive_engines": [["brave","too many requests"],["startpage","CAPTCHA"]]
}
So is SearXNG a Google SERP API?
Here's my honest take after living with it. SearXNG is a wonderful piece of software for what it's designed to do: private, aggregated, ad-free search you fully control. If that's your goal, self-host it today. And its JSON output is a real, usable self-hosted serp api for low-volume, DuckDuckGo-flavored results.
But if what you actually typed into a search box was "free Google SERP API," SearXNG isn't it — not without work you're signing up to do forever. From one IP you get JSON-off-by-default, a crash-on-default-engine, and Google/Brave/Startpage locked behind CAPTCHAs. Getting to reliable Google JSON means running your own proxy infrastructure and engine tuning, which is a project, not a config line. For a genuinely free entry point without that operational tail, a hosted free tier is the shorter path — we compared the honest ones in 7 free Google search API tiers, tested and SERP APIs with a free tier and no minimum.
And when you do want structured Google results without operating anything, the call looks like this — a live response, already parsed into JSON:
import requests
r = requests.get(
"https://apiserpent.com/api/search/quick",
params={"q": "best serp api", "country": "us"},
headers={"X-API-Key": "YOUR_API_KEY"},
timeout=40,
)
data = r.json()
print(data["engine"]) # google
for row in data["results"]["organic"][:3]:
print(row["position"], row["title"], row["url"])
# 1 Best SERP API 2026 — Independent Comparison ... https://serpapi.cc/
# 2 Best SERP APIs 2026: 12 Tested, Ranked by Real Cost https://cloro.dev/...
# 3 8 Best SERP APIs in 2026 https://www.scrapingbee.com/...
Same JSON shape you were trying to coax out of SearXNG — title, url, position — but from Google, with no engine to un-break and no CAPTCHA to route around. That's the whole build-vs-buy line: SearXNG hands you the software; a SERP API hands you the results.
Want Google JSON without operating a scraper?
Serpent is a pay-as-you-go SERP API — structured Google, Bing, Yahoo and DuckDuckGo results, up to 100 per call, no proxies to source and no engines to un-break. Self-host SearXNG for private search; reach for Serpent when you need reliable Google data as JSON. 10 free searches, then from $0.60 per 1,000.
Get Your Free API KeyExplore: SERP API · Pricing · Playground
FAQ
Can you use SearXNG as a SERP API?
Yes — SearXNG has a JSON output that works as a self-hosted SERP API, but it's off by default and you enable it in settings.yml by adding json to search.formats. It also needed the limiter disabled and an X-Forwarded-For header before it answered automated requests. It works, but it's a metasearch aggregator you operate, not a managed API.
Is SearXNG a good free Google SERP API?
As private search, it's excellent. As a Google SERP API, it's limited: from a single IP the Google engine returned zero parseable results, Brave and Startpage were suspended with too-many-requests and CAPTCHA errors, and only DuckDuckGo returned results reliably. Out of the box it behaves more like a DuckDuckGo proxy unless you add your own proxy pool.
How do I enable the JSON API in SearXNG?
Edit settings.yml, add a search block with formats set to a list containing html and json, set a secret_key, and set limiter: false for automated access. Restart the container and /search?format=json returns JSON instead of a 403.
Why does my SearXNG query return a 500 error?
Usually a failed engine. In this test the wikidata engine's init got a 403, so it never registered, and every default query then crashed with KeyError: 'wikidata' and a 500. Restrict the query to working engines with engines=duckduckgo, or remove the broken engine from settings.yml.
How fast is a self-hosted SearXNG query?
The aggregation layer added roughly 0.74–0.89s per query here, a median near 0.83s, because it fans out to several engines and waits. Fine for interactive search; slower than a purpose-built SERP API for high-volume automated collection.
Is SearXNG's number_of_results field reliable?
No. It returned 0 even when the results array held 10 entries. Count the array length yourself.



