Know what your internet really delivers.
Run periodic internet speed test, store, display results with builtin web server.
This aims to be small, efficient all-in-one program (statically linked, includes web assets) written in rust. The intent is to allow monitoring of your internet connection as easy as possible. You can use speedketchup for one-off test or keep it running continuously to spot any changes in your internet connection.
What it measures: the internet connection of the machine speedketchup runs on. Every test goes from that machine to a speedtest.net server on the internet, the same servers the speedtest.net website and apps use. The web page only shows the results - opening it, or starting a test from it, does not measure the link between your browser and speedketchup, so Wi-Fi between them does not count. To measure the internet connection rather than a Wi-Fi link, run it on a machine wired to the router, or on the router or NAS itself.
Prebuilt executables for some platforms:
| platform | executable | upx-compressed executable | app store |
|---|---|---|---|
| linux x86_64 | 448k | 195k | |
| linux i686 | 439k | 201k | |
| linux aarch64 | 460k | 187k | |
| linux arm | 439k | 196k | |
| linux mips | 592k | 223k | |
| linux mipsel | 592k | 226k | |
| windows x86_64 | 500k | 238k | Microsoft Store |
| macos app, universal (x86_64 + aarch64) | 707k |
/metrics: download and upload speed, idle and loaded latency, server and isp, test and failure countsusage: speedketchup [options] -h|--help: print this -v|--version: print version -i|--interval <minutes>: test interval in minutes, 10 by default, counted from the last test in the results file after a restart -f|--file <filename>: file to store test results in, speedketchup-results.csv by default -a|--address <local_addr>: address to listen on for incoming connections, 127.0.0.1 by default local_addr: use 0.0.0.0 to accept connections on all addresses -p|--port <port>: port to listen on for incoming connections, 8288 by default -s|--server <server_host[:server_port]>: speedtest server to use, avoids automatic server selection if specified server_host: domain_name|ipv4_addr|ipv6_addr server_port: port number, 8080 by default -dd|--download-duration <seconds>: how long to test download speed, 0 disables test, 10 seconds by default -ud|--upload-duration <seconds>: how long to test upload speed, 0 disables test, 10 seconds by default -dc|--download-connections <number>: how many parallel connections to make for download, 8 connections by default -uc|--uplaod-connections <number>: how many parallel connections to make for upload, 8 connections by default -iu|--influx-url <url>: also write every result to this InfluxDB line protocol write url, http only eg http://influxdb:8086/api/v2/write?org=home&bucket=speedketchup -it|--influx-token <token>: token for the influx url, sent as 'Authorization: Token <token>' -mq|--mqtt <host[:port]>: also publish every result to this mqtt broker, with home assistant discovery port: 1883 by default, plain mqtt only -mu|--mqtt-user <user>: user name for the mqtt broker -mp|--mqtt-password <password>: password for the mqtt broker every option can also be given as an environment variable, command line options take precedence: SPEEDKETCHUP_INTERVAL, SPEEDKETCHUP_FILE, SPEEDKETCHUP_ADDRESS, SPEEDKETCHUP_PORT, SPEEDKETCHUP_SERVER, SPEEDKETCHUP_DOWNLOAD_DURATION, SPEEDKETCHUP_UPLOAD_DURATION, SPEEDKETCHUP_DOWNLOAD_CONNECTIONS, SPEEDKETCHUP_UPLOAD_CONNECTIONS, SPEEDKETCHUP_INFLUX_URL, SPEEDKETCHUP_INFLUX_TOKEN, SPEEDKETCHUP_MQTT, SPEEDKETCHUP_MQTT_USER, SPEEDKETCHUP_MQTT_PASSWORD
/metrics serves the last test in the prometheus text format:
download and upload speed in bits per second, idle, download and upload latency
in seconds, the server and isp as labels on speedketchup_last_test_info, and
test and failure counts. Run with -a 0.0.0.0 so the scraper can reach it.
scrape_configs:
- job_name: speedketchup
static_configs:
- targets: ["speedketchup-host:8080"]
Anything that scrapes prometheus or OpenMetrics endpoints can collect it, for example:
With --influx-url every result is also written as one
line protocol
point, right after it is saved to the csv:
speedketchup,server=LIVAS/Riga/Latvia,server_host=speedtest.livas.lv:8080,isp=Tele2 download_mbps=40.6,upload_mbps=39.0,latency_idle_ms=44.2,latency_download_ms=71.7,latency_upload_ms=98.9,client_ip="203.0.113.7" 1792775257000000000
The values are rounded like in the csv, fields of a disabled test are left out,
and a failed test is a point with just an error string field. A write that
fails is logged and not retried, the csv still has the result.
The url is the complete write url, so the same option covers every server that
takes line protocol over http. Put the token in --influx-token or
SPEEDKETCHUP_INFLUX_TOKEN, it is sent as Authorization: Token <token>:
| server | write url |
|---|---|
| InfluxDB 2 | http://influxdb:8086/api/v2/write?org=home&bucket=speedketchup + token |
| InfluxDB 3 Core / Enterprise | http://influxdb:8181/api/v2/write?bucket=speedketchup + token |
| InfluxDB 1 | http://influxdb:8086/write?db=speedketchup, add &u=user&p=password with auth enabled |
| VictoriaMetrics | http://victoriametrics:8428/write, it has no strings, client_ip and error turn up as series that are always 0 |
| QuestDB | http://questdb:9000/write |
| Telegraf influxdb_listener | http://telegraf:8186/write, and from there to any Telegraf output |
Only http is supported, for InfluxDB Cloud or anything else behind https write to a local Telegraf and let it forward.
With --mqtt every result is also published to an MQTT broker, with
Home Assistant discovery
messages, so a SpeedKetchup device shows up in Home Assistant by itself:
download and upload speed, latency idle and while downloading and uploading,
the time of the last test, a problem sensor that is on when the last test
failed, and the server and isp.
With the Mosquitto broker add-on of Home Assistant, the broker is the Home Assistant host and the user is a Home Assistant user, best one made for it:
speedketchup -mq homeassistant.local -mu speedketchup -mp <password>
The result goes to speedketchup/state as json, the discovery configs under
homeassistant/, all retained, so a Home Assistant that restarts gets them
from the broker. The speed and latency sensors go unavailable when there was no
successful test for two intervals. The sensors of a test disabled with -dd 0
or -ud 0 are removed. speedketchup connects for every result and disconnects
when the broker has acknowledged it. Only plain mqtt is supported, no TLS.
SpeedKetchup.app runs in the menu bar, with no Dock icon and no terminal. The menu shows the last result and the time to the next test, the live speeds during a test, opens the web page, runs a test right away, starts SpeedKetchup at login and opens its settings file.
The settings and results are in ~/Library/Application Support/SpeedKetchup.
speedketchup.conf takes the same SPEEDKETCHUP_... variables as the
environment, one per line, and the app applies them as soon as the file is
saved. A bad value, or a port another program has, is shown in red in the
menu. The web page is on 127.0.0.1:8288.
The app is signed with a Developer ID and notarized by Apple. The binary in it is the same macos universal binary, which runs from a terminal too.
SpeedKetchup is in the Microsoft Store. It runs in the notification area of the taskbar, with the same menu as the macOS app: the last result and the time to the next test, the live speeds during a test, the web page, a test right away, start at login and the settings file, which opens in Notepad. The settings work the same way, a bad value or a port another program has is shown in red in the menu, and the web page is on 127.0.0.1:8288.
The app also adds speedketchup to the command line, it runs in the terminal
when started from one.
A plain make gives you a binary for the machine you are on.
The release binaries are smaller than that: they are built on a pinned rust
nightly with -Z build-std, -Zlocation-detail=none and
-Cpanic=immediate-abort, which rebuilds the standard library without the
panic formatting machinery.
make release # every released binary, needs a mac make macos # just the macos universal binary make app # SpeedKetchup.app in bin/SpeedKetchup-macos.zip make linux # just the linux + windows binaries
The linux and windows binaries are cross built inside the container image in
build/Dockerfile - make linux builds that container image and re-enters make inside
it, so the only thing needed on the host is container
on macos, or CONTAINER=docker (or podman) anywhere else. The container image carries the
cross toolchains, a musl built for the tier 3 mips targets, upx and qemu-user -
every binary is run once before the build is considered done. Everything lands
in ./bin.
Official container image: gatispei/speedketchup on Docker Hub.
The container image is FROM scratch: one layer holding the statically linked binary and
an empty /data for the results volume, nothing else. No shell, no libc, no
base container image underneath. Built for linux/amd64, linux/386, linux/arm64 and
linux/arm/v6.
make image
That cross builds the binaries and assembles the manifest with the same
container runtime as the rest of the build. With docker, point it at buildx:
make image IMAGE_BUILD="docker buildx build".
docker volume create speedketchup docker run -p 8080:8080 -v speedketchup:/data gatispei/speedketchup
Packages for x86_64, arm_64 and arm-x41 QNAP NAS are attached to every release. To install and update SpeedKetchup from the App Center, add the repository in App Center > Settings > App Repository:
https://speedketchup.com/qnap/repo.xml
The packages are not signed by QNAP, so on QTS 4.5 and later first tick
“Allow installation of applications without a valid digital signature” in
App Center > Settings > General. The web page is on port 8288, the settings are in
speedketchup.conf in the SpeedKetchup folder.
make qpkg
builds the packages from the linux binaries in ./bin with QNAP’s QDK.
How speedketchup compares with other periodic testers, from their documentation and source as of October 2026:
| speedketchup | speedtest-tracker | Speedtest-Tracker v2 | MySpeed | Netronome | Speedmon | |
|---|---|---|---|---|---|---|
| written in | rust | php (laravel) | go, nuxt | javascript | go, react | python |
| speed test | own speedtest.net client | Ookla cli | Ookla cli | Ookla cli, LibreSpeed, Cloudflare | speedtest.net (speedtest-go), iperf3, LibreSpeed | Ookla cli |
| runs as | single static binary, container image, macOS app, windows exe, QNAP package | container image | container image | linux, windows, container image | binaries for linux, macOS, freebsd, windows, container image | python, container image |
| container image size | 0.23 MB | 67 MB | 35 MB | 62 MB | 46 MB | 83 MB |
| results stored in | csv | sqlite, mysql, mariadb, postgresql | sqlite, postgresql | sqlite, mysql | sqlite, postgresql | only the backends below |
| web page with charts | ✓ | ✓ | ✓ | ✓ | ✓ | - (grafana) |
| prometheus metrics | ✓ | ✓ | ✓ | ✓ | - | - |
| InfluxDB | ✓ v1, v2, v3 and other line protocol servers | ✓ v2 | - | - | - | ✓ v1, v2, graphite |
| MQTT, Home Assistant | ✓ with discovery | - | - | - | MQTT notifications only | - |
| notifications | - | mail, discord, slack, telegram, ntfy, gotify, pushover, apprise, webhook, healthchecks | webhook, healthchecks | mail, signal, whatsapp, telegram | discord, ntfy, gotify, pushover, mail, mqtt, webhook and more | - |
| login | - (127.0.0.1 by default) | ✓ | optional, OpenID Connect | optional password | ✓ local or OpenID Connect | - |
| also | acts as a speedtest server | thresholds, packet loss, translations | api, opentelemetry tracing | multiple servers, retention period | packet loss, traceroute, dns monitoring, remote agents | |
| latest release | 0.5, Oct 2026 | 1.15.1, Oct 2026 | 2.4.2, Oct 2026, as tags and container images only | 1.0.9, May 2024 | 0.16.0, Oct 2026 | no releases, last change Jan 2022 |
All of them measure from the machine they run on, their web page only shows the results. The self-hosted test servers further down are the other way around, they measure between a browser and the server.
The Ookla cli based ones need its license accepted, speedketchup talks to the speedtest.net servers itself. Container image sizes are the compressed linux/amd64 download from the registry.
Prometheus exporters:
One-off command line testers:
Self-hosted test servers, they measure the link between a browser and your own server rather than your internet connection: