OpenSERP: a self-hosted SERP API for Google, Bing, Yandex, Baidu, DuckDuckGo and Ecosia
Self-hosted SERP API for AI, SEO & automation. Browser-rendered Google, Bing, Yandex, Baidu, DuckDuckGo and Ecosia search with page extraction 🎉
At a glance
- What is it?
- OpenSERP is an MIT-licensed Go server and CLI that renders search engine pages in a browser and returns structured JSON, markdown or NdJSON. It is a good fit for teams that want search results on localhost without per-query billing, and a poor fit for anyone who wants a managed service with a support contract.
- Who is it for?
- Adopt OpenSERP if you want search results over HTTP on your own machine, can run a headless Chromium container, and are prepared to handle CAPTCHAs and proxy rotation yourself. Do not adopt it if you need a vendor SLA, a per-query invoice, or a drop-in replacement for a managed SERP API with guaranteed uptime.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem OpenSERP addresses, and who ends up using it
Commercial SERP APIs charge per search and cover a fixed set of engines. OpenSERP takes the opposite position: you run the scraper yourself, on your own machine, and pay nothing per query. The README describes it as a "free, open-source SERP API and CLI for Google, Yandex, Baidu, Bing, DuckDuckGo, and Ecosia" with "no API keys, no per-search billing".
The audience is narrower than that sentence suggests. Three groups show up in the repository's own examples directory: people wiring search into an LLM or agent (examples/ai), SEO practitioners tracking rankings across engines (examples/seo), and developers who need page content rather than just links (examples/content, examples/media). If you are building a product where a search outage is a revenue event, a self-hosted scraper is the wrong foundation. If you are prototyping an agent that needs to look things up, or running rank checks on a schedule you control, the economics change completely.
One detail matters for the second group: the same JSON schema is used across all six engines, so a rank tracker does not need six parsers. The README lists "Dedicated endpoints for six engines, same JSON schema across all of them" as the first feature. That is the actual product claim, not the absence of billing.
How the server renders and returns results
OpenSERP is a Go binary with a Fiber HTTP server in front of per-engine scrapers. The repository root contains one directory per engine (google/, bing/, yandex/, baidu/, duckduckgo/, ecosia/) plus core/, extract/ and cmd/. The dependency list tells you the mechanism: github.com/go-rod/rod drives a real Chromium, github.com/bogdanfinn/tls-client and fhttp handle TLS-level requests, goquery parses HTML, and go-trafilatura with html-to-markdown converts fetched pages into readable text.
So the flow is: a request hits an endpoint, the relevant engine package builds a search URL, Chromium loads the page (or a TLS-client request fetches it), the HTML is parsed into a common result struct, and the server serializes it. The Dockerfile confirms the browser dependency by building on top of chromedp/headless-shell:stable and pinning OPENSERP_APP_BROWSER_PATH=/headless-shell/headless-shell so Rod does not try to download its own Chromium at runtime.
The megasearch endpoint is the interesting piece of architecture. A single call fans out to several engines, then merges and dedupes the results into clusters. In the README's example response each cluster carries a canonical_url, the engines that returned it, a best_rank and a score. That is a real deduplication model, not a concatenated list, and it is what makes cross-engine rank comparison practical.
The response also records what went wrong: meta.engines_responded and meta.engines_failed are separate arrays. Partial failure is a first-class outcome rather than a 500.
Installing OpenSERP with Docker and running a first megasearch
The fastest path is the prebuilt image on Docker Hub. The README publishes it as karust/openserp, and the command below starts the API server bound to all interfaces inside the container on port 7000, mapped to loopback on the host.
docker run --rm -p 127.0.0.1:7000:7000 karust/openserp:latest serve -a 0.0.0.0 -p 7000If you prefer Compose, the repository ships a docker-compose.yaml that mounts ./config.yaml read-only into /usr/src/app/config.yaml and sets OPENSERP_SERVER_HOST to 0.0.0.0 and OPENSERP_SERVER_PORT to 7000. Note the comment in that file: Chrome crashes with "Out of memory" when /dev/shm is the default 64MB, so the service sets shm_size: 2gb rather than sharing the host IPC namespace.
services:
openserp:
container_name: serp
init: true
shm_size: 2gb
image: karust/openserp:latest
ports:
- 7000:7000
command: serve -lThere is also a Go install path if you would rather not run containers. The README gives this pair of commands, and the second one is a complete first use: it searches DuckDuckGo from the CLI and prints markdown instead of JSON.
go install github.com/karust/openserp@latest
openserp search duckduckgo "open source serp api" --format markdownOnce the server is up, the first HTTP request worth making is the megasearch call from the README. It asks Bing and Google for "golang vs rust", requests page extraction, and uses mode=any so the response comes back as soon as one engine answers.
curl "http://127.0.0.1:7000/mega/search?engines=bing,google&text=golang+vs+rust&extract=1&mode=any"With mode=any the example response shows engines_responded containing only bing, with google absent and engines_failed empty. That is the expected shape: you get an answer quickly, and the meta block tells you which engines actually contributed. The container also exposes /health, which the Dockerfile's HEALTHCHECK polls with wget every 30 seconds.
Where OpenSERP breaks down
The dependency on a real browser is the source of most operational pain. Chromium needs memory and shared memory; the Compose file's 2GB shm_size is not decoration. Run the image with default settings on a small VM and the documented failure mode is an out-of-memory crash during page loads.
CAPTCHAs are the second wall. The go.mod includes github.com/2captcha/2captcha-go, which tells you the project anticipates solving challenges through a paid third-party service. That is a cost and a dependency the "no per-search billing" framing does not mention. It also means the effective price of a query is not zero once an engine starts challenging you.
Proxies are the third. The docker-compose.yaml contains a commented block for a proxies.entries list with url and tags fields, including a google.proxy key that points an engine at a named proxy group. It is commented out, which is a fair signal that proxy setup is expected to be manual and that you will need your own pool. The README does not document rollback or a fallback path when every configured proxy is exhausted.
Finally, scope. OpenSERP scrapes public result pages. It is not a crawler, it does not maintain an index, and it cannot answer questions about pages that no engine has indexed. If your requirement is "search my own corpus", this is the wrong tool entirely.
OpenSERP compared with SearXNG
SearXNG is the comparison people actually search for, and the architectural difference is clean. SearXNG is a metasearch front end: it queries other search engines' APIs and HTML endpoints and aggregates what comes back, with a strong emphasis on privacy and on not profiling the user. It is a Python application, and it is designed to be a search page for humans first.
OpenSERP is a scraper that returns an API response. It renders result pages in Chromium, parses them into a typed schema, and hands you JSON, markdown, text or NdJSON. The output is meant for a program, not a person. Where SearXNG's value is aggregation and privacy, OpenSERP's value is the structured fields: rank, domain, favicon, domain_info with tld and sld, per-result engine attribution, and the cluster objects that tell you which engines agreed on a URL.
That difference decides the choice. If you want a private search page for a team, SearXNG. If you want a callable endpoint that returns ranked, typed results and optionally the markdown of the target pages, OpenSERP. They are not interchangeable, and running both is not unreasonable.
Licence, upgrades and what maintenance looks like
OpenSERP is MIT licensed, which is permissive: you can use it commercially, modify it and redistribute it, provided the copyright notice and permission notice are preserved. The LICENSE file at the repository root is the authoritative text, and nothing here is legal advice. One practical consequence of MIT plus a scraping core: the licence places no restriction on what you do with the software, but it says nothing about the terms of service of the engines you point it at. That obligation stays with you.
Upgrade cost is moderate. The last release listed is v0.8.12 on 2026-07-22, following v0.8.6 in June and v0.8.3 earlier that month, so the release cadence through mid-2026 was frequent. The last push to the repository was on 2026-07-22. Because the code pins a specific headless-shell digest in the Dockerfile, pulling a new OpenSERP image does not silently change your browser build; you have to update the base image deliberately. That is a good property for reproducibility and a chore for security patching.
The Go module requires go 1.24.1 with toolchain go1.24.6, so building from source needs a recent toolchain. The Makefile exposes build, test, lint, run and fmt targets, and test-integration runs only when OPENSERP_INTEGRATION_TESTS=1 is set, which means the default test run does not hit live engines.
Editorial conclusion
Adopt OpenSERP if you want search results over HTTP on your own machine, can run a headless Chromium container, and are prepared to handle CAPTCHAs and proxy rotation yourself. Do not adopt it if you need a vendor SLA, a per-query invoice, or a drop-in replacement for a managed SERP API with guaranteed uptime. Before committing, verify that the six engines you care about still return organic results from your network, that your /dev/shm allocation is large enough for Chromium, and that your use of the extracted page content complies with each site's terms.
Frequently asked questions
What are the key differences between OpenSERP and SearXNG?
OpenSERP is a scraper that returns a structured API response with fields such as rank, domain and engine attribution, plus optional markdown extraction of the target pages. SearXNG is a metasearch front end aimed at private search for people. The README positions OpenSERP as an API and CLI for LLMs, SEO and automation rather than a search page.
Is there an open-source SERP API available?
OpenSERP is one: the README describes it as a free, open-source SERP API and CLI for Google, Yandex, Baidu, Bing, DuckDuckGo and Ecosia, with no API keys and no per-search billing. It is MIT licensed and can be self-hosted via Docker or installed with go install.
How do I install OpenSERP with Docker?
Pull the prebuilt image from Docker Hub as karust/openserp and run it with the serve subcommand, or use the docker-compose.yaml shipped in the repository. The Compose file sets shm_size to 2gb because Chrome crashes with an out-of-memory error when /dev/shm is the default 64MB.
Does OpenSERP need an API key or a paid account?
No. The README states there are no API keys and no per-search billing when you self-host. A hosted version with the same API exists at openserp.org/cloud for people who would rather not run the infrastructure.
How does OpenSERP handle CAPTCHAs?
The module depends on github.com/2captcha/2captcha-go, so CAPTCHA solving is routed through that paid service when an engine challenges a request. The README does not document a fallback for engines that fail, and the response records failures in meta.engines_failed rather than retrying silently.
What output formats does OpenSERP support?
The README lists JSON, Markdown, Text and NdJSON. The CLI takes a --format flag, as in openserp search duckduckgo "open source serp api" --format markdown, and the HTTP API returns JSON by default.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/karust-openserp)