Measure network latency and DNS resolution performance of public DNS-over-HTTPS (DoH) resolvers — directly in your browser.
race is a fully client-side benchmarking tool for DNS-over-HTTPS (RFC 8484) and JSON-based DNS APIs. It tests 200+ public resolvers, ranks them by latency in real time, and verifies that each one actually resolves DNS correctly. No backend, no tracking, no data leaves your browser.
Live demo: viktor45.github.io/race
- Dual-layer testing
- Network latency — round-trip time of a connectivity probe to each resolver
- DNS resolution — a real DNS query for your chosen domain to verify the resolver actually works (
✅ DNS OK/⚠️ DNS failed)
- 200+ built-in resolvers — curated from the curl DoH wiki and refreshed automatically every week
- Live results — the list re-sorts by latency as results arrive, with color-coded progress bars:
- 🟢 ≤ 50 ms — excellent
- 🟡 ≤ 150 ms — acceptable
- 🔴 > 150 ms — slow
- Summary & filtering — live stats (tested / fastest / median / failed), filter chips by speed class, and search by URL
- Custom inputs — upload your own server list (
servers.txt) and test against your own domain(s) - CSV export & sharing — save the results as CSV, or share them via the system share sheet where the browser supports it
- Light / dark theme — follows your OS preference, with a manual toggle that remembers your choice
- Works offline — installable PWA with a service worker cache, an install button, an offline indicator, and an in-app update notification
- Zero dependencies — plain HTML/CSS/JS, no build step
Open viktor45.github.io/race, click Start Test, and wait for the results.
git clone https://github.com/viktor45/race.git
cd race
python3 -m http.server 8000Then open http://localhost:8000.
⚠️ Don't openindex.htmlviafile://— the app loads its resolver list withfetch(), which browsers block for local files. Any static HTTP server works (npx serve,php -S, nginx, etc.).
- Click Start Test to benchmark the built-in resolver list.
- (Optional) Open Settings to:
- upload your own
servers.txt— one DoH URL per line, e.g.https://1.1.1.1/dns-query - set a domain to validate against (default:
example.com), or upload adomains.txtfile
- upload your own
- Watch results appear and sort themselves by latency. Hover over a latency value to see the DNS status of that resolver. Use the filter chips or the search field to narrow the list.
- Click Cancel to stop a run early, Export CSV to download the results, or Share to send them via the system share sheet.
- (Optional) Click Install in the top bar to install the app and use it offline.
For each resolver, the tool runs two checks:
- Connectivity probe — a
no-corsHEADrequest, falling back to ano-corsGET. Most public resolvers don't send CORS headers, and a browser can't tell a CORS block apart from a real network failure, so the probe deliberately avoids CORS mode: an opaqueno-corsresponse resolves whenever the server answers at all, which proves reachability and measures the round-trip time regardless of CORS. Servers that simply don't allow CORS still get a latency in ms; only genuinely unreachable servers (DNS failure, connection refused, timeout) are reported as unreachable. - DNS validation — a real DNS query for your test domain:
- URLs containing
/resolveare treated as JSON DNS APIs (?name=…&type=A) - everything else is queried via RFC 8484 (
POSTwith anapplication/dns-messagebody built in the browser)
- URLs containing
Resolvers are tested in batches of 5 with a 5-second timeout per request, to avoid browser throttling and to be fair to public infrastructure.
The default list lives in data/servers.txt and contains 200+ public resolvers — Cloudflare, Google, Quad9, AdGuard, NextDNS, ControlD, Mullvad, and many more.
It is regenerated automatically every week from the curl DoH wiki by a GitHub Actions workflow, so the built-in list stays current without any manual work.
index.html single-page entry point
src/script.js all application logic
src/style.css styling and theming
src/theme.js applies the saved theme before first paint
sw.js service worker (offline cache) — must stay at repo root
src/manifest.json PWA manifest
data/servers.txt built-in resolver list (auto-generated, do not edit by hand)
data/servers.sh script that regenerates servers.txt from the curl wiki
images/ icons and favicons
The app is static — deploy it anywhere that serves files. This repository ships a GitHub Actions workflow (.github/workflows/static.yml) that deploys to GitHub Pages on every push to main. If you fork the repo, enable Pages under Settings → Pages with the source set to GitHub Actions.
GPL-3.0 — see LICENSE.
- Resolver list: curl/curl Wiki — DNS-over-HTTPS
- Icons: Material Symbols
🔒 Everything runs locally in your browser. No telemetry, no analytics, no data sent anywhere except the resolvers you test.