SSD Nodes Learn Hosting plans →
Guides Matt ConnorBy Matt Connor

Public SearXNG instances: how to choose one

How to read searx.space before you pick a public SearXNG instance: what each grade measures, and the one thing about the operator no grade can show you.

How to choose a public SearXNG instance

To choose a public SearXNG instance, start at searx.space, read the HTML grade first, and then check which search engines really returned results in the last test run. A V in the HTML column means every static file the page sends you comes from the SearXNG git repository. The timing data shows whether Google, or any other engine you care about, works there today. No grade tells you what the operator logs. The last step is a decision about the person who runs the server.

SearXNG is a metasearch engine: it sends your query to other search engines and merges their answers. A public instance is one that somebody else runs for anyone to use. If you are not sure how SearXNG relates to the older project, read the difference between searx and SearXNG. This guide covers the user side. The operator side, meaning what a person who runs an instance should lock down, is in hardening a public SearXNG instance.

Where is the list of public SearXNG instances?

The list lives at searx.space. The same data is published as a raw feed at https://searx.space/data/instances.json. The web page is a view of that feed. So anything you read in a column is also a field you can query. On 2026-10-23 the main table showed 67 online instances.

The page shows no last-updated date, but the feed does. Its top level has two keys, metadata and instances. The field metadata.timestamp holds the time of the test run as a Unix timestamp.

Download the feed and read it with jq

The page is fine for browsing. For a question like "which instances return Google results today", the feed is better. jq, a command-line JSON processor, answers that kind of question in one line.

sudo apt update && sudo apt install -y curl jq
curl -s https://searx.space/data/instances.json -o instances.json
jq -r '.metadata.timestamp | todate' instances.json
jq '.instances | length' instances.json

The third command prints the time of the test run as a date in UTC. Check it first. You want to know how old the data is before you trust it. The fourth command prints how many records the feed holds. This number is larger than the count of online instances on the page, because instances that failed the check are still in the feed.

.instances is an object, and its keys are the instance URLs. You look up one instance by its URL, with the trailing slash:

jq '.instances["https://searx.mbuf.net/"].timing' instances.json

A record holds a timing block, a network block, and one block for each grade: tls, http and html. Some instances did not answer the test, for example because the request timed out. Their record has an error field and no timing or network block, so the command above prints null for them. It also prints null when the URL is not in the feed at all.

What does the TLS grade measure?

TLS (transport layer security) is the encryption between your browser and the instance. searx.space does not grade it by itself. Its cryptcheck_backend.py fetcher asks a cryptcheck-backend API and stores two fields, grade and gradeUrl. The link opens https://cryptcheck.fr/https/<host>, where you can read the full report.

The check can return several results for one host. The fetcher takes the grade from each result, removes duplicates, sorts the grades worst first and joins them with commas. So a cell that reads B, A means at least one result scored B. The first grade in the cell is the one that counts. A ? means the lookup failed. It does not mean the TLS setup is bad.

A good TLS grade protects your query on the way to the instance. It says nothing about what happens to the query after it arrives.

What does the CSP grade measure?

The page calls this column the CSP grade. CSP is Content Security Policy, an HTTP header that tells the browser which scripts and files a page may load. In the feed, the same data sits under the http key. The page credits it as a "Grade from the MDN HTTP Observatory", and the code agrees. The mozillaobs.py fetcher sends the host to the Mozilla HTTP Observatory v2 API and keeps grade, score and gradeUrl. The link opens observatory.mozilla.org/analyze/<host> with the full result.

Results are cached on disk for 24 hours. So if an operator fixes their headers today, the grade on the page may not change until a later run.

The HTML grade: is the operator changing the code?

This is the column to read first. The page heading asks it as a question: "Are the scripts and static files well-known?" The checker fetches the scripts and static files of the instance, hashes them, and compares each hash with known SearXNG releases and known forks.

The code in external_resources.py gives one letter. It is chosen by the first rule that matches, in this order:

  1. The eye icon (👁️): analytics software was flagged. This rule wins over all the others.
  2. V: every resource is well-known, which means it matches a known release.
  3. F: at least one resource matches a known fork, and every resource is either a fork file or a well-known file.
  4. ?: no resources were found at all, which points to a fetch problem.
  5. E: at least one resource is loaded from another host.
  6. Cjs: at least one script has a hash that matches nothing known.
  7. C: at least one other file has a hash that matches nothing known.

After the letter, the code can add a suffix. It adds js? when a script could not be fetched. It adds ? when another file could not be fetched and there is no ? yet. A suffix means part of the page was not checked, so the letter in front of it covers less than the whole page.

The page legend words some of this differently. It defines V as vanilla, with all static files from the SearXNG git repository. It defines C as "Some static files have been modified, but the Javascripts comes from the SearXNG git repository", and Cjs as modified static files that include JavaScript. The comments in the code describe Cjs as a reference to an external script and C as a reference to an external resource. The condition the code actually tests is an unknown hash. Trust the condition. The legend also says that only inline scripts and external scripts (<script src=...>) are checked.

Why V or F against E or Cjs is the column that matters

Everything the page runs in your browser is code that the operator chose to serve. This is what the letters mean for you as a reader. The project itself does not state it this way.

A V or F means every checked script and file matches public code that other people can read. A Cjs means at least one script matches nothing known. You would be running code in your browser that nobody outside the operator has reviewed. An E means the page loads something from another host. That host then receives a request from your browser each time you open the page.

The rules form a chain, so only one letter appears. Suppose an instance loads a file from another host and also serves an unknown script. It shows E, because the E rule comes before the Cjs rule. An E can hide a Cjs.

The HTML grade only checks what reaches your browser. A V instance runs clean code in your browser, but the grade cannot see what the server does with your query.

Which engines actually answer? Reading the timing data

The timing data is the most useful part of the feed. It shows whether searches work, not only whether the front page loads.

timing.search is the general test. The checker sends up to five searches for the word time with the simple theme. It stops early after more than three errors. From the results it builds working_engine_names: the sorted set of engine names found on the result entries. Empty names and names that start with wiki are left out. working_engines is the length of that list, and success_percentage is the share of requests that passed the check.

timing.search_go is a separate Google test. It sends two searches for !google time. The !google part is a bang, which tells SearXNG to ask the Google engine only. A request fails with A result is not from the google if any real result did not come from Google. It fails with No result if there were no results. search_go has no list of engine names.

When we read the feed on 2026-10-23, the general search test of https://searx.mbuf.net/ showed an empty working engine list ("working_engine_names": []) and the error No result, and its Google test failed with No result as well. Instances change from one run to the next, so run the command above for your own candidate.

One trap: google cse is a different engine from google. An instance can list google cse and still fail the Google test, so match the exact name. If you later run your own server and see engines drop out of this list, engine CAPTCHA errors on a SearXNG server are one place to start.

How many public SearXNG instances return Google results?

This guide does not print a count. The feed changes with every run, so a number copied into a page goes stale quickly. Count it yourself from the file you just downloaded. There are two tests, and they can give different answers, so say which one you mean when you quote a number.

The strict test: the exact engine name google appears in the working engines of the general search.

jq '[.instances[] | select((.timing.search.working_engine_names // []) | index("google") != null)] | length' instances.json

The dedicated test: the Google check passed at least once.

jq '[.instances[] | select((.timing.search_go.success_percentage // 0) > 0)] | length' instances.json
jq -r '.instances | to_entries[] | select((.value.timing.search_go.success_percentage // 0) > 0) | "\(.key) \(.value.timing.search_go.success_percentage)"' instances.json

The last command prints each instance that passed, followed by its success percentage. The // [] and // 0 parts give a default value to instances that have no timing block, so the filter does not fail on them. Those instances count as not working, which is correct, because they did not answer the test. If Google results matter to you, the dedicated test is the one to use.

Response times and uptime

The page defines its time columns like this. Initial response time is the time to load the front page with no existing connection. Search response time is the time for a query with the default engines. Google response time is the time for the Google engine. Each time is split into parts. Total is the time measured by the client, Server is the time the instance took to serve the page, and Load is the time spent loading third-party pages, such as Google.

Two more values come from those. Network time is Total minus Server. Processing time is Server minus Load. A high Load time means the upstream engines were slow. A high Processing time points at the instance itself. Network time is measured from the checker, so it says more about the distance between the checker and the server than about your own connection.

These numbers come from one checker. They do not show how the instance treats you. An instance with a busy rate limiter may answer you with 429 Too Many Requests, and SearXNG rate limits and 429 errors explains what that error means.

IPv6, country and network: what the ASN flag means

The IPv6 column reads "Yes if at least one IPv6 is valid and has the HTTPS port opened." The country comes "From whois information of the IPs." That is where the address block is registered, which is not always where the machine stands.

The network column shows the provider name, but the page does not explain it. The feed adds one field, network.asn_privacy. An ASN (autonomous system number) is the number that identifies one network on the internet. The field holds a value from the AsnPrivacy enum in searxstats/model.py: BAD = -1, UNKNOWN = 0, GOOD = 1.

The ASN list lives in searxstats/data/asn.py. Every entry in it is marked BAD, and every entry is a CDN (content delivery network), such as Akamai, Cloudflare, Fastly or Google Cloud CDN. The file header says the list was built from bgp.he.net and the Wikipedia article on CDNs, and it warns that it "May contains some errors, doesn't contains all ASN with privacy issue." Nothing in the file is marked GOOD.

So the field can flag a known CDN, but it cannot vouch for a network. A 0 means the network is not on the list. It is not a pass. Why a CDN counts as bad: a CDN that proxies a site ends the TLS connection at its own servers, so it handles your query as well as the operator does.

How does searx.space sort the list?

The page states its sort order. Instances are sorted by:

  1. HTML grade.
  2. The default /search returns results.
  3. TLS grade.
  4. CSP grade.
  5. Monthly uptime, in 5% steps.
  6. SearXNG version from this month or the previous month.
  7. At least 3 working engines in the default search.
  8. The Google engine returns results.
  9. Response time of the default /search.
  10. Response time of the Google engine.

The top of the table is therefore the instances with clean code and working search. It is not a ranking of privacy, because nothing about logging appears in this list.

How does an instance get listed?

Operators ask to be added by opening an issue in the searxng/searx-instances repository on GitHub. The README there sets the rules. "All new instance requests must wait 2 weeks before being added." A reviewer marks the request with a wait-2-weeks label, and checks after two weeks that the instance stayed up to date. New instances must "allow the IPs of check.searx.space to access your instance", because that is the checker that fills in every column. An instance that was removed earlier comes back only when it "meets the uptime requirement of >95% (16.8h)."

A listing means the instance passed these checks. It is not a recommendation. The maintainers say this themselves, as the next section shows.

Onion instances

Some entries have a .onion URL instead of a normal domain. These are Tor onion services. You open them in Tor Browser, and searx.space labels them "Hidden Service" and gives them an "Online Tor" link in its navigation. Count them in your copy of the feed:

jq '[.instances | keys[] | select(contains(".onion"))] | length' instances.json

In the feed we read, several onion entries had Tor errors or no timing data at all. Some onion entries are mirrors of a normal instance run by the same operator. For example, search.jeremyh.xyz and its onion address had identical engine lists. An onion address changes the network path between you and the instance. It does not change who runs the instance or what they can see. For the server side of this, read how an onion service runs on a VPS.

Why can an instance's country and provider change?

In an October 2023 discussion in the SearXNG repository (#2926, "Help me understand how i should chose my instance?"), a user reported that instances had moved from Swiss networks to Icelandic or US networks. A maintainer answered that the country and the provider "can change without notice". Another suggested that users write a program that watches the instances.json feed and reports changes. A third maintainer wrote: "We can't and don't want to give a recommendation for one and against the other instance."

You can do that watching with two commands. Save the network block of your instance today:

URL="https://searx.mbuf.net/"
curl -s https://searx.space/data/instances.json | jq --arg u "$URL" '.instances[$u].network' > "network-$(date +%F).json"

Run it again next month and compare the two files with diff. A changed IP address or a changed asn_cidr line means the instance moved to another network. That is a good moment to read its record again.

What no grade measures: what the operator logs

The instance has to receive your query, because it forwards the query to the search engines. So whoever runs the server can read it. None of the columns on searx.space measures what the operator logs or how long they keep it. The sort order has no logging rule, and the listing rules have none either. The TLS grade protects the query on the way to the server. The HTML grade checks the code in your browser. Neither one reaches the server's log files.

That leaves trust in a person you have probably never met. Some operators publish a privacy policy, which is a promise you cannot check. For what the operator can see and what SearXNG does by design, read whether SearXNG is safe to use.

When to stop shopping and run your own

Stop shopping when the list keeps failing you. Three signs are common. You need Google results, and the dedicated test passes on few instances or none. You switch instances every few weeks because one stopped working or moved. Or you are not willing to trust a stranger with your queries.

Your own instance answers the logging question, because you set the logging. It also lets you pick the engines, and which SearXNG engines to enable and disable helps with that choice. Self-hosting SearXNG on a VPS walks through the install. If you only want a private search front end and do not need SearXNG itself, compare SearXNG, Startpage and DuckDuckGo first.

FAQ

What does the V grade mean on searx.space?

V is the HTML grade for an instance where every checked script and static file has a hash that matches a known SearXNG release. It means the page code that reaches your browser is public, unchanged code. It does not tell you anything about the server, so a V instance can still log your queries.

Why does a public SearXNG instance show no Google results?

searx.space runs a separate Google test, stored as timing.search_go, that sends !google time twice. Many instances fail it with No result or A result is not from the google. Download https://searx.space/data/instances.json and filter on timing.search_go.success_percentage above 0 to find instances where Google answered in the last run. Note that google cse is a different engine from google.

Is an instance with an A+ TLS grade safe to use?

The TLS grade comes from cryptcheck.fr and only measures the encryption between your browser and the instance. It protects your query on the way there. It does not measure what the operator logs, and no other column on searx.space measures that either.

Is a .onion SearXNG instance more private?

An onion instance hides your IP address from the operator, because your traffic reaches it through Tor. The operator still receives every query you type. Some onion entries are mirrors of a normal instance run by the same person, so the onion address changes the network path, not who can read your searches.

Was this article useful?