All notable changes to this fork are documented here. The format follows Keep a Changelog; this fork continues from upstream taganaka/SpeedTest 1.15.
- Line quality test —
--qualityand--quality-server host:portreport the latency spread (min / avg / max), jitter and packet loss over a burst of 60 pings, reconnecting mid-burst so losses are counted instead of aborting the run. Both flags were advertised in--helpbefore but were never implemented:--qualityprinted the usage text and exited with a failure, and--quality-serverwas rejected as an unrecognized option. - Sub-millisecond ping resolution (
SpeedTestClient::pingMicros). The old whole-millisecond rounding made every sample on a fast link read as 0–1 ms, which left the quality figures meaningless. - IPv6 support. Sockets were hardcoded to
AF_INET, so IPv6-only servers and IPv6-only clients could never connect.host:portparsing now also accepts IPv6 literals, bracketed ([2606:9340:1002::10]:8080) or bare. - Portable static binaries via
Dockerfile.static(docker build -f Dockerfile.static -o dist .). musl-based, no shared library dependencies at all, verified on Alpine, Fedora and Debian. musl is used deliberately: glibc'sgetaddrinfoneeds NSS plugins at runtime and does not link statically in a reliable way. - Runtime CA store detection (
CaCerts.h). A static binary otherwise carries the certificate path of the distro it was built on; the trust store is now located at run time, so HTTPS keeps verifying certificates on any host.
- Certificate verification was effectively random.
strict_ssl_verifywas never initialised, soCURLOPT_SSL_VERIFYPEERreceived whatever happened to be on the stack — TLS verification was silently disabled whenever that byte was zero. It now defaults to on, and--insecureremains the explicit opt-out. - Every server appeared to be ~9000 km away.
api.ipapi.ismoved from its nested response shape (location.latitude,company.name) to a flat one (lat,lon,company_name,cc). The parser swallowed the failure and left the client at latitude 0, so distances — and therefore the nearest-server ordering — were computed from the Gulf of Guinea. Both shapes are now accepted. The ISP name had gone blank for the same reason. - Connecting to an unreachable host could block for minutes; connects now time
out after 5 seconds (
SpeedTest_CONNECT_TIMEOUT_SEC). --test-server hostwithout a port silently used port 0 instead of 8080.- Failed IP lookups now report the underlying curl error, with a hint about
ca-certificates/--insecurewhen the cause is a missing trust store.
-DENABLE_STATIC=ONproduces a genuinely static binary where static libraries exist. It previously used pkg-config's*_STATIC_LIBRARIES(which loses link order) and still pulled in the sharedlibssl.sofromfind_package(OpenSSL), so-staticcould not link at all. On distros without static libraries it now warns and points atDockerfile.static.- Release workflow publishes static
x86_64andaarch64binaries with checksums, and takes its release notes from this file.
- Interactive server picker, the default when running in a terminal: arrow
keys or
j/kto move,Enterto select,/to filter,sto cycle the sort order (distance / ping / city / sponsor),rto re-ping,ato ping everything,qto quit. Pings are measured lazily for visible rows on eight worker threads and update live.--no-selectkeeps the old automatic lowest-ping behaviour, and that is also the fallback when there is no terminal (a pipe, cron, a script). --list[=N]— table of the nearest servers with a real measured ping.--city NAME— restrict candidates to servers matching a city, sponsor, country or host name.--lastand--history[=N]— review previous results without re-testing. Every completed run is appended to$XDG_STATE_HOME/speedtest++/history.jsonl(~/.local/stateby default).- Live progress display: an npm-style spinner with the current aggregate
throughput, replacing the row of dots. Falls back to dots when stdout is not a
terminal and stays silent for
--output text|json. - Yandex Internetometer mode (
--yandex) for networks where speedtest.net is unreachable, based on internetometer-cli. Probe URLs from the API are accepted only over HTTPS from Yandex-owned hosts, and redirects are disabled. When a Russian IP is detected, the normal run suggests the mode. - Shell completions for fish and zsh, installed by
make install. - A restyled result card,
--output jsonsupport throughout, and--insecure.
- Server versions were compared as floats, so
2.11 < 2.3and every current speedtest server was rejected as too old. Latency-based selection therefore never actually compared servers —bestServer()silently returned the nearest one. Versions are now compared component by component. - The server list only ever contained 10 servers. The legacy XML endpoint picks those itself, and nearby cities were missing from it entirely. The list now comes from the JSON API (~70 servers around the client), with the XML endpoint kept as a fallback.
- Segfault on an unresolvable host:
gethostbyname_rcan report success and leaveresultempty, which the code then dereferenced. close()left the descriptor set, so a laterconnect()returned success on a dead socket.--test-serverno longer reportsPing: 0 msfor a server it cannot reach; it fails with a clear message and fills in the server's details from the list.
cmake_minimum_requiredraised to 3.10; a fresh clone would not configure at all with the previous 2.7.