Drives Firefox Nightly to run the @cloudflare/speedtest library (loaded from esm.sh via a local HTML page), records throughput, latency, jitter, plus per-measurement points, and saves structured JSON results. A separate report.py renders the JSON files as a self-contained HTML report (summary table + boxplots).
- Direct baseline — works (
uv run main.py). - HTTP/3 variant — works (
uv run main.py --h3, points the library atbastion.h3.speed.cloudflare.com). - In-browser VPN (IP protection) — works (
uv run main.py --vpn), routes speedtest traffic through Firefox's IP protection / Fastly proxy. Today the proxy hop is HTTP/2 CONNECT-over-TLS (read out of Firefox's connection table at the end of the run and surfaced in the report); MASQUE / connect-udp support will come later.
- Linux x86_64
- uv
- Python 3.11+
Firefox Nightly and geckodriver are downloaded on first run into .cache/.
The VPN runs need a Firefox profile that's already signed in and has the feature flipped on. Do this once:
env LD_LIBRARY_PATH='' ./.cache/firefox/firefox -profile ./profile
Then in that Firefox window:
- Go to
about:config, setbrowser.ipProtection.enabled = true. - Sign in to a Firefox Account.
- Quit Firefox cleanly (releasing the profile lock).
The persistent profile lives at ./profile/ (gitignored) and is reused across runs. --vpn runs toggle the proxy on; runs without --vpn turn it off.
uv run main.py # direct baseline
uv run main.py --h3 # force h3.speed.cloudflare.com endpoint
uv run main.py --vpn # route through IP protection
uv run main.py --vpn --h3 # (currently downgrades to h2 over tunnel)
uv run main.py --debug # tiny measurement set; for plumbing changes
Output JSON files land in results/, named <tag>-<utc-timestamp>.json where <tag> composes direct, optionally vpn, and optionally h3.
uv run report.py
Writes results/report.html (self-contained, Plotly JS inlined). Summary table shows colo, client IP, origin HTTP version, proxy hop (for --vpn runs), throughput, latency, and jitter per run; boxplots show per-request bandwidth by transfer size and latency distributions.
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT License (LICENSE-MIT)
at your option.