How to enable the SearXNG JSON API
SearXNG answers in HTML until JSON output is enabled, and a request with format=json returns 403 Forbidden. This guide enables the JSON API in settings.yml, tests it with curl and connects the instance to AI agents with searxNcrawl.
Why format=json returns 403 Forbidden
SearXNG serves a result format only if settings.yml lists it under search.formats. Its search API documentation says that a request for a format that is not enabled returns 403 Forbidden, and that many public instances have these formats disabled. The fix therefore needs an instance whose settings you control.
The HTML page of SearXNG is made for people in a browser. Scripts and AI agents need the same results as data: the JSON API returns the merged hits of every engine the instance queries, with their sources and scores, in one answer that a program can parse without scraping. Tools built on SearXNG, from command-line clients to MCP servers such as searxNcrawl, depend on it, which is why a missing json entry stops all of them with the same 403.
Step 1: run SearXNG
If you have no instance yet, start one in a container as described in the SearXNG Docker guide. The instance answers on port 8888, and its configuration in ./config/ is mounted as /etc/searxng/ inside the container.
docker run --name searxng -d \ -p 8888:8080 \ -v "./config/:/etc/searxng/" \ -v "./data/:/var/cache/searxng/" \ docker.io/searxng/searxng:latest
The -d flag runs the container in the background, and --name searxng gives it the name that the restart in step 3 uses. Port 8888 on the host maps to port 8080 inside the container; if 8888 is taken, choose another host port and use it in every address on this page. The data directory keeps the cache between restarts.
Step 2: enable JSON in settings.yml
Open ./config/settings.yml and list json under search.formats, next to html for the browser interface. Format names are lower case; csv and rss are enabled the same way (settings reference).
search:
formats:
- html
- jsonStep 3: restart and test
Restart the container so SearXNG reads the new settings, then ask for JSON. A JSON object with a results array means the API works; 403 Forbidden means the format list was not picked up.
docker restart searxng curl -s 'http://localhost:8888/search?q=searxng&format=json' | head -c 300
What the JSON response contains
The answer is one JSON object. results holds the hits: each with url, title, content (the snippet), the engine that ranked it first, every engine in engines that found it, a merged score, the category and, where an engine supplies it, publishedDate. Alongside the results, answers, corrections, infoboxes and suggestions carry what the engines add beyond plain links. Shortened to one result, an answer looks like this:
{
"query": "searxng",
"results": [
{
"url": "https://github.com/searxng/searxng",
"title": "...",
"content": "...",
"engine": "google cse",
"engines": ["google cse", "duckduckgo"],
"score": 3.0,
"category": "general",
"publishedDate": null
}
],
"answers": [],
"corrections": [],
"infoboxes": [],
"suggestions": [],
"unresponsive_engines": [["brave", "Suspended: too many requests"]]
}unresponsive_engines names every engine that failed for this query, with the reason. Upstream engines rate-limit or challenge a new instance from time to time; the other engines still answer, so the results stay usable.
Scripts and agents usually need only url, title and content; keep the other fields for ranking and debugging. Results found by several engines carry a higher score, a quick signal for where the engines agree.
Query parameters of the JSON API
Both / and /search accept these parameters, as URL query parameters with GET or as form data with POST (search API reference):
- q
- The search query; required
- format
- json, csv or rss; each must be listed under
search.formats, or the answer is 403 - categories
- Comma-separated list of the categories to search, for example general or news
- language
- Language code of the results; the default comes from
settings.yml - pageno
- Page of the results, starting at 1
- time_range
- day, month or year
- safesearch
- 0, 1 or 2; the default comes from
settings.yml
A GET request is enough for most uses: URL-encode the query, add format=json and fetch the next page with pageno=2. POST sends the same parameters as form data, so the query does not appear in the URL. To serve feed readers or spreadsheets as well, list rss or csv under search.formats too; each format is enabled on its own, as the 403 for csv in our test shows.
If the test still fails
- 403 Forbidden:
jsonis missing undersearch.formats, or the file you edited is not the one mounted as/etc/searxng/settings.yml. - 429 Too Many Requests: the limiter, enabled with
server.limiter, throttles suspicious clients. Add the address of your agent host topass_ipin/etc/searxng/limiter.toml. - No answer from another container: address SearXNG by its container name on a shared network, not by localhost.
- A public instance: use your own. Public instances often disable JSON and rate-limit automated requests.
Keep the instance private
On its first start the container writes a short settings.yml with use_default_settings: true and a random server.secret_key; keep that key secret and leave the file in the mounted directory, so it survives updates of the image. SearXNG has no API keys, so anyone who reaches port 8888 can use your instance and the reputation of its address. Bind it to localhost or a private network, or put a reverse proxy with authentication in front of it.
If several agents or people share the instance, consider the limiter. It needs a Valkey database configured in settings.yml and limits suspicious traffic per client address, so the upstream engines are less likely to block or challenge your instance. Clients you trust, such as the host of your agents, go into pass_ip in limiter.toml and keep unrestricted access. Behind a reverse proxy, forward the client address in X-Forwarded-For and X-Real-IP; otherwise every request looks as if it came from the proxy.
Does SearXNG need an API key?
No. SearXNG has no API keys and no setting for one: whoever reaches the instance can query it. In our test a request without any key and a request with a made-up X-API-Key header both answered 200 with results. Guides that mention such a header describe a proxy or a wrapper in front of SearXNG, not SearXNG itself.
To limit who may search, put a reverse proxy with authentication in front of the instance. With Caddy that takes a shared network, a password hash and a short Caddyfile. Create the network and the hash first:
docker network create searxng-net docker network connect searxng-net searxng docker run --rm caddy:2 caddy hash-password --plaintext 'choose-a-password'
Write the hash into a file named Caddyfile next to the config directory. The proxy listens on port 8080 in its container and forwards authenticated requests to the SearXNG container by its name:
:8080 {
basic_auth {
agent <hash from caddy hash-password>
}
reverse_proxy searxng:8080
}docker run --name searxng-auth -d --network searxng-net \
-p 8889:8080 -v "./Caddyfile:/etc/caddy/Caddyfile" caddy:2
curl -s -o /dev/null -w '%{http_code}\n' -u agent:choose-a-password \
'http://localhost:8889/search?q=searxng&format=json'In our run the proxy answered 401 without credentials and with a wrong password, and 200 with the right one. Then publish only the proxy: start SearXNG with -p 127.0.0.1:8888:8080, or without -p at all, so the port without a password is not reachable from other machines. searxNcrawl sends the credentials as basic authentication:
SEARXNG_URL=http://localhost:8889 SEARXNG_USERNAME=agent \ SEARXNG_PASSWORD=choose-a-password uvx --from searxncrawl search "model context protocol"
Without the two variables the same search failed with the message that SearXNG authentication failed and that SEARXNG_USERNAME and SEARXNG_PASSWORD should be checked; with them it returned results. For a token in a header instead, for example the one of an API gateway, set SEARXNG_EXTRA_HEADERS.
Connect the JSON API to AI agents
searxNcrawl is an open-source MCP server that uses this JSON API: point SEARXNG_URL at the instance and your agents get the search tool, plus crawl and crawl_site for page content in Markdown. Try a search from the shell first:
SEARXNG_URL=http://localhost:8888 uvx --from searxncrawl search "model context protocol" --max-results 5
Then run uvx searxncrawl setup to register the server with Claude Code, Codex, Gemini CLI, Cursor, VS Code and Claude Desktop. The SearXNG MCP server page shows the setup for each client.
searxNcrawl sends format=json together with language, safe search and page with every search, so the only change on the SearXNG side is the format list. If the instance sits behind basic authentication, set SEARXNG_USERNAME and SEARXNG_PASSWORD; for a token in a header, for example the one of a tunnel or gateway, use SEARXNG_EXTRA_HEADERS, which can read the value from a file.
How we tested this guide
We ran every step on 2026-11-04 with the image docker.io/searxng/searxng:latest (SearXNG 2026.9.15) and searxNcrawl 0.33.1. Before step 2, format=json answered 403 Forbidden; after the restart it answered 200 with 20 results, while format=csv, still not listed, kept answering 403. For the section on API keys we put Caddy 2.11.7 with basic authentication in front of the same instance.
We reviewed these facts on 2026-11-04 against the linked sources. Our editorial and corrections policy says how we keep them current and fix errors.
Frequently asked questions
Is the SearXNG JSON API enabled by default?
No. SearXNG serves HTML until json is listed under search.formats in settings.yml; until then a request with format=json answers 403 Forbidden.
How do I fix 403 Forbidden for format=json in SearXNG?
Add json under search.formats in the settings.yml that your instance actually loads (in the container /etc/searxng/settings.yml), restart SearXNG and repeat the request with format=json.
Can I use the JSON API of a public SearXNG instance?
Rarely. The SearXNG documentation warns that many public instances have these formats disabled, and public instances also rate-limit automated requests. Run your own instance for agents and scripts.
Does the SearXNG JSON API need an API key?
No. SearXNG has no API keys: whoever can reach the instance can query it. Keep it on a private network or behind authentication; searxNcrawl can send SEARXNG_USERNAME and SEARXNG_PASSWORD or extra headers.