Engineering
SearXNG vs DuckDuckGo: Differences, Setup and Agent Search
Choose DuckDuckGo for a search website you can use immediately. Choose SearXNG when you want to operate a metasearch service and control its upstream engines. For a Python application or a local AI agent, DDGS is a third option: a library that queries external search services without requiring you to host a separate search server.
DuckDuckGo and DDGS are different things. The DDGS project, formerly duckduckgo_search, supports multiple search backends. Using DDGS does not necessarily mean using DuckDuckGo.
SearXNG vs DuckDuckGo at a glance
| Question | DuckDuckGo | SearXNG | DDGS |
|---|---|---|---|
| What is it? | A hosted search service | A metasearch application you can host | A Python metasearch library |
| How do you use it? | Visit the website | Open an instance or call its HTTP API | Call the library from your application |
| Who operates the search interface? | DuckDuckGo | You, or a public-instance operator | You run the library |
| Can you choose upstream engines? | The service manages its sources | Yes, through instance configuration | Yes, through supported backends |
| What setup is needed? | None for browsing | A running instance; maintenance if you host it | A Python environment |
| Structured results for an agent? | The website is not a drop-in SearXNG JSON endpoint | JSON when enabled by the operator | Python result objects |
| Do web queries leave your machine? | Yes | Yes, when searching external engines | Yes, when searching external providers |
For ordinary browsing, DuckDuckGo is the easier starting point. SearXNG makes sense when choosing engines and operating your own interface are worth the maintenance. A public SearXNG instance removes that maintenance, but you still depend on its operator and policies.
Which should an AI agent use?
For a single local MCP client, start with DDGS if you want the least infrastructure. For a shared endpoint, SearXNG gives you an HTTP interface and central control over which engines the service queries. Neither choice guarantees better relevance or uninterrupted access: results depend on the upstream engines, query, region and availability.
TinySearch supports both. Its native pip and uvx installations default to DDGS; the Docker quick start uses a bundled SearXNG instance. The agent first calls search to discover URLs, then scrape_urls to read selected pages and retrieve evidence. Follow the local LLM and Open WebUI setup guide for the client connection.
Enable the SearXNG JSON API
On an instance you operate, merge this into its existing settings.yml, then restart SearXNG. Keep the rest of your configuration:
search: formats: - html - jsonTest the instance directly before connecting an agent. Replace the address below with the address and port of your instance:
curl --fail-with-body --get 'http://localhost:8080/search' \ --data-urlencode 'q=SearXNG documentation' \ --data-urlencode 'format=json'Expect a JSON object containing a results array; inspect unresponsive_engines if the results are unexpectedly empty. A valid response does not guarantee a nonempty result for every query. The SearXNG Search API documentation explains the request parameters and the 403 response returned when a requested format is disabled. Public instances may deliberately disable JSON access.
Connect TinySearch to that instance
For an MCP client that launches a stdio process, configure TinySearch with the endpoint reachable from that process:
{ "mcpServers": { "tinysearch": { "command": "uvx", "args": ["--python", "3.12", "--from", "tinysuite-search[server]", "tinysearch"], "env": { "TINYSEARCH_SEARCH_BACKEND": "searxng", "SEARXNG_URL": "http://localhost:8080/search" } } }}This JSON shape is for clients accepting mcpServers; Open WebUI instead connects to TinySearch over HTTP as described in the linked tutorial. If TinySearch runs in Docker, localhost means that container. On a shared Docker network, use the SearXNG service name and internal port, such as http://searxng:8080/search.
The TinySearch configuration reference also covers search_engines, search_region and search_backend_fallback. For the searxng backend, enabled fallback handles request failures and empty responses reporting unresponsive engines. A genuine empty response without those errors remains empty. An optional Brave API fallback requires credentials and is still subject to the provider’s limits.
Troubleshoot empty results, HTML and rate limits
| Symptom | Check first | Next step |
|---|---|---|
| 403 requesting JSON | Is json enabled in search.formats? |
Enable it on your instance and restart; otherwise check access controls |
| HTML instead of JSON | Does the request include format=json? |
Test /search directly and inspect proxy responses |
| Connection refused | Is the host and port reachable from TinySearch? | Correct the container address or start the service |
| Empty results with engine errors | Which engines appear in unresponsive_engines? |
Inspect those engines and retry with lower concurrency |
| 429, throttling or CAPTCHA | Did the instance or an upstream provider reject the request? | Back off and review the relevant service’s limits |
SearXNG’s limiter handles incoming requests to the instance. Upstream search engines apply their own controls. Changing the instance limiter does not remove upstream limits, and no universal delay guarantees reliable searches. DDGS requests can also fail or be throttled.
What stays local?
Self-hosting gives you control over the search application. It does not create an offline web index. SearXNG forwards web queries to external engines, DDGS contacts its providers, and fetching a result contacts the destination website. Local embeddings keep that ranking step on your machine; they do not keep search queries there.
Choose the backend using your own workload. Compare the same queries, record versions and enabled engines, and inspect useful results, errors and latency. This guide explains configuration and tradeoffs; it does not claim a measured speed or relevance winner. For the retrieval stage after search, see what TinySearch adds to Crawl4AI.