Skip to content

pacnpal/speedtest-cli

 
 

Repository files navigation

speedtest-cli

Command line interface for testing internet bandwidth using speedtest.net.

Latest tag Supported Python versions Apache 2.0 license Last commit Open issues GitHub stars
  • Measure download speed, upload speed, and latency against speedtest.net.
  • Filter to specific servers by ID, or exclude known-bad ones.
  • Run against a self-hosted Speedtest Mini server.
  • Bind to a specific source IP address.
  • Machine-readable output: JSON and CSV, for logging, graphing, and scripting.
  • Use as a library from Python to automate periodic speed tests.
  • Secure by default: all communication with speedtest.net uses HTTPS, with optional hardened XML parsing via defusedxml.
  • Python 3.9 or newer. Tested on CPython 3.9 through 3.13 and on PyPy3.
  • Internet access to speedtest.net.
  • Optional: defusedxml. When installed, the XML configuration and server list responses are parsed through defusedxml for defence in depth. Without it, speedtest-cli falls back to the Python standard library's xml.etree.ElementTree parser.

No other third-party packages are required at runtime.

This is a hardened fork maintained at pacnpal/speedtest-cli with Python 3.9+ support, HTTPS by default, and optional defusedxml hardening. It is not the build published to PyPI under the name speedtest-cli — that is still upstream. Install directly from this repository.

From GitHub with pip

pip install git+https://github.com/pacnpal/speedtest-cli.git

or pin to a specific tag:

pip install git+https://github.com/pacnpal/speedtest-cli.git@<tag>

From a local clone

git clone https://github.com/pacnpal/speedtest-cli.git
cd speedtest-cli
pip install .

Single-file download

The module is also distributed as a single, dependency-free script. Drop it anywhere on your PATH:

curl -Lo speedtest-cli https://raw.githubusercontent.com/pacnpal/speedtest-cli/master/speedtest.py
chmod +x speedtest-cli

(Substitute wget -O for curl -Lo if you prefer.)

The script uses a shell/Python polyglot shebang, so it runs on systems that only ship versioned interpreters (python3.13, python3.12, …) instead of a plain python binary. It tries python3 first, then python3.13 through python3.9, and finally python. ./speedtest-cli will therefore Just Work on modern distributions that no longer ship /usr/bin/python.

Optional: defusedxml hardening

speedtest-cli uses defusedxml for XML parsing when it is available and falls back to the standard library parser otherwise. To install the tool together with defusedxml in one step, use the hardened extra:

pip install 'speedtest-cli[hardened] @ git+https://github.com/pacnpal/speedtest-cli.git'

or, if you already installed speedtest-cli from this repo, just:

pip install defusedxml
$ speedtest-cli -h
usage: speedtest-cli [-h] [--no-download] [--no-upload] [--single] [--bytes]
                     [--share] [--simple] [--csv]
                     [--csv-delimiter CSV_DELIMITER] [--csv-header] [--json]
                     [--list] [--server SERVER] [--exclude EXCLUDE]
                     [--mini MINI] [--source SOURCE] [--timeout TIMEOUT]
                     [--secure] [--no-secure] [--no-pre-allocate] [--version]

Command line interface for testing internet bandwidth using speedtest.net.
--------------------------------------------------------------------------
https://github.com/pacnpal/speedtest-cli

options:
  -h, --help            show this help message and exit
  --no-download         Do not perform download test
  --no-upload           Do not perform upload test
  --single              Only use a single connection instead of multiple. This
                        simulates a typical file transfer.
  --bytes               Display values in bytes instead of bits. Does not
                        affect the image generated by --share, nor output from
                        --json or --csv
  --share               Generate and provide a URL to the speedtest.net share
                        results image, not displayed with --csv
  --simple              Suppress verbose output, only show basic information
  --csv                 Suppress verbose output, only show basic information
                        in CSV format. Speeds listed in bit/s and not affected
                        by --bytes
  --csv-delimiter CSV_DELIMITER
                        Single character delimiter to use in CSV output.
                        Default ","
  --csv-header          Print CSV headers
  --json                Suppress verbose output, only show basic information
                        in JSON format. Speeds listed in bit/s and not
                        affected by --bytes
  --list                Display a list of speedtest.net servers sorted by
                        distance
  --server SERVER       Specify a server ID to test against. Can be supplied
                        multiple times
  --exclude EXCLUDE     Exclude a server from selection. Can be supplied
                        multiple times
  --mini MINI           URL of the Speedtest Mini server
  --source SOURCE       Source IP address to bind to
  --timeout TIMEOUT     HTTP timeout in seconds. Default 10
  --secure              Use HTTPS when communicating with speedtest.net
                        operated servers (default, kept for backward
                        compatibility)
  --no-secure           Use HTTP instead of HTTPS. Not recommended —
                        speedtest.net may reject plain HTTP requests and
                        results can be tampered with in transit
  --no-pre-allocate     Do not pre allocate upload data. Pre allocation is
                        enabled by default to improve upload performance. To
                        support systems with insufficient memory, use this
                        option to avoid a MemoryError
  --version             Show the version number and exit

Run a normal test and print the full human-readable output:

speedtest-cli

Concise one-line summary:

speedtest-cli --simple

Emit JSON for a logging pipeline:

speedtest-cli --json

Emit CSV with a custom delimiter:

speedtest-cli --csv-header
speedtest-cli --csv --csv-delimiter ';'

Test against a specific server (by ID):

speedtest-cli --server 1234

List available servers sorted by distance:

speedtest-cli --list

Run against a local Speedtest Mini instance:

speedtest-cli --mini http://speedtest.local/mini

Bind outgoing connections to a specific interface address:

speedtest-cli --source 192.168.1.100

The CLI is a thin wrapper around the speedtest module. The same functionality is available to import directly:

import speedtest

s = speedtest.Speedtest()
s.get_best_server()
s.download()
s.upload()

results = s.results.dict()
print(f"Download: {results['download'] / 1_000_000:.2f} Mbit/s")
print(f"Upload:   {results['upload']   / 1_000_000:.2f} Mbit/s")
print(f"Ping:     {results['ping']:.2f} ms")

Pick a specific server, then run the test:

s = speedtest.Speedtest()
s.get_servers(servers=[1234])   # filter to one server ID
s.get_best_server()
s.download()
s.upload()
print(s.results.json())

Useful constructor arguments:

  • secure (default True) — use HTTPS for all speedtest.net traffic. Pass False only if you have a specific need for HTTP; speedtest.net increasingly rejects plain-HTTP requests.
  • source_address — an IPv4/IPv6 string to bind outgoing sockets to (equivalent to the --source CLI flag).
  • timeout — HTTP timeout in seconds (default 10).
  • shutdown_event — a threading.Event the caller sets to stop in-flight download/upload threads early.

The SpeedtestResults object exposed as s.results provides dict(), json(pretty=False), csv(delimiter=','), and share() methods. share() POSTs the run to speedtest.net and returns a https://www.speedtest.net/result/<id>.png URL.

HTTPS by default. All connections to speedtest.net-operated hosts (config, server list, latency probes, download/upload endpoints, share API) use HTTPS. Earlier versions defaulted to plaintext HTTP, which leaked the client's IP and ISP in the clear and let a network attacker tamper with the ping target or swap the chosen test server. The --secure flag is retained as a backward-compatible no-op; the --no-secure flag opts out and is not recommended — speedtest.net may refuse plain-HTTP requests and results can no longer be trusted against an on-path attacker.

Hardened XML parsing. If defusedxml is installed, speedtest-cli routes XML parsing through it to reject DTDs, external entity references, and entity-expansion bombs before they reach the standard-library parser. Without defusedxml the tool falls back to xml.etree.ElementTree.fromstring, which is already safe in modern Python for the kinds of documents speedtest.net returns, but defusedxml adds an extra belt-and-suspenders layer.

Certificate verification. TLS connections use the system trust store via Python's ssl.create_default_context() with hostname verification enabled. There is no fallback to unverified TLS.

It is not a goal of this application to be a reliable latency reporting tool.

Latency reported by this tool should not be relied on as a value indicative of ICMP-style latency. It is a relative value used for determining the lowest-latency server for performing the actual speed test against.

There is the potential for this tool to report results inconsistent with Speedtest.net. Several factors contribute to the potential inconsistency:

  1. Speedtest.net has migrated to using pure socket tests instead of HTTP-based tests.
  2. This application is written in Python.
  3. Different versions of Python will execute certain parts of the code faster than others.
  4. CPU and memory capacity and speed will play a large part in inconsistency between speedtest.net and even other machines on the same network.

Issues relating to inconsistencies will be closed as wontfix without additional reason or context.

Clone the repository and run the test suite via tox:

git clone https://github.com/pacnpal/speedtest-cli.git
cd speedtest-cli
pip install tox
tox                       # run against all available Python versions
tox -e py312              # a specific CPython version
tox -e pypy3              # PyPy3
tox -e flake8             # lint only

The default tox environment byte-compiles the module, runs a live speed test against speedtest.net, and executes tests/scripts/source.py (a portable smoke test of the --source error path). See tox.ini and CONTRIBUTING.md for details.

Apache License, Version 2.0. See LICENSE for the full text.

About

Command line interface for testing internet bandwidth using speedtest.net

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages