The upload test reported low and unstable numbers on Safari (macOS and iOS) while the download test was correct. Cause: the "start" handler in speedtest_worker.js matched every Safari user agent and set settings.forceIE11Workaround = true. In ulTest() that flag selects a fundamentally different, less accurate measurement path: instead of sending one xhr_ul_blob_megabytes blob (20 MB by default) and accumulating event.loaded from upload.onprogress, it sends a stream of 256 KB requests and adds a fixed 256 KB to totLoaded on each onload. Progress is therefore quantised to whole requests and each request pays a full round trip before the next one starts, so on fast or high-latency links the measured speed is both too low and noisy. The workaround is not needed. Its comment claims it is only required for MPOT, but the block never checked settings.mpot. The same block also excludes crios and fxios, which on iOS run the very same WebKit networking stack as Safari, so the user agent test cannot have been guarding an engine-level bug in the first place. Current WebKit implements xhr.upload.onprogress, and the existing feature detection in ulTest() (the try/catch that probes xhr.upload.onprogress) already selects the workaround for browsers that genuinely lack it, without sniffing. Changes: - Remove the Safari user agent block. Safari now takes the regular upload path, the same one Chrome and Firefox on iOS already took. - Guard the Edge and PlayStation 4 blocks with typeof s.forceIE11Workaround === "undefined", matching how the other quirks avoid clobbering explicitly passed settings. Previously an explicit forceIE11Workaround: false in the start command was silently overwritten, so the workaround was not switchable from outside the worker. Default behaviour for those browsers is unchanged. - Add tests/e2e/worker-browser-quirks.spec.js, which loads the worker under spoofed user agents and asserts the resolved settings. - Update doc.md so Safari is no longer listed as affected. The Edge and PlayStation 4 blocks are deliberately left outside the enable_quirks condition: those browsers have no working upload.onprogress, so running them with enable_quirks: false would report 0 or Fail rather than a less precise number. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1bUKsok59shM69PwLMMRM |
||
|---|---|---|
| .github | ||
| .logo | ||
| backend | ||
| docker | ||
| examples | ||
| frontend | ||
| images | ||
| results | ||
| tests | ||
| .eslintrc.json | ||
| .gitignore | ||
| .prettierignore | ||
| .prettierrc.json | ||
| config.json | ||
| design-switch.js | ||
| DESIGN_SWITCH.md | ||
| DEVELOPMENT.md | ||
| doc.md | ||
| doc_docker.md | ||
| Dockerfile | ||
| Dockerfile.alpine | ||
| favicon.ico | ||
| index-classic.html | ||
| index-modern.html | ||
| index.html | ||
| LICENSE | ||
| manifest.webmanifest | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.js | ||
| README.md | ||
| server-list.json | ||
| settings.json | ||
| speedtest.js | ||
| speedtest_worker.js | ||
| stability.html | ||
| stability_worker.js | ||
LibreSpeed
No Flash, No Java, No Websocket, No Bullshit.
This is a very lightweight speed test implemented in Javascript, using XMLHttpRequest and Web Workers.
Try it
Compatibility
All modern browsers are supported: IE11, latest Edge, latest Chrome, latest Firefox, latest Safari. Works with mobile versions too.
Features
- Download
- Upload
- Ping
- Jitter
- IP Address, ISP, distance from server (optional)
- Telemetry (optional)
- Results sharing (optional)
- Multiple Points of Test (optional)
- Connection stability test with latency charting, loss tracking, threshold alerts, and CSV export
Server requirements
- A reasonably fast web server with Apache 2 (nginx, IIS also supported)
- PHP 5.4 or newer (other backends also available)
- MariaDB or MySQL database to store test results (optional, Microsoft SQL Server, PostgreSQL and SQLite also supported)
- A fast! internet connection
Installation
Assuming you have PHP and a web server installed, the installation steps are quite simple.
- Download the source code and extract it
- Copy the project files to your web server's shared folder (ie.
/var/www/html/speedtestfor Apache), keeping the layout as it is in the repository. The modern UI loads its assets fromfrontend/, so that directory is copied as a whole rather than unpacked. - Optionally, copy the results folder too, and set up the database using the config file in it.
- Be sure your permissions allow read and execute access where needed.
- Visit YOURSITE/speedtest/index.html and voila!
Installation Video
This video shows the installation process of a standalone LibreSpeed server: Quick start installation guide for Debian 12
More videos will be added later.
Android app
A template to build an Android client for your LibreSpeed installation is available here.
CLI client
A command line client is available here.
.NET client
A .NET client library is available in the LibreSpeed.NET repo (NuGet), maintained by MemphiZ.
Development
If you want to contribute or develop with LibreSpeed, see DEVELOPMENT.md for information about using npm for development tasks, linting, and formatting.
Design switch
LibreSpeed supports both the classic and modern UI. The root index.html acts as a lightweight switcher and redirects to index-classic.html or index-modern.html based on config.json (useNewDesign) or URL overrides (?design=new / ?design=old). For architecture and deployment details (including Docker behavior), see DESIGN_SWITCH.md.
Stability test
LibreSpeed includes a standalone connection stability test at stability.html, linked from both the classic and modern interfaces. It repeatedly measures ping over a selected duration and reports current, average, minimum, maximum, jitter, and failed request percentage values with a live chart.
The stability test can target the local LibreSpeed backend, one of the configured multiple points of test, or built-in external targets such as Google, Cloudflare, and Apple. It also supports optional latency threshold alerts and CSV export of the collected samples. Docker deployments copy stability.html and stability_worker.js into the web root and reuse the same server list configuration as the main UI.
Docker
A docker image is available on GitHub, check our docker documentation for more info about it.
The image is built every week to include an updated version of the ipinfo-DB used for ISP detection. Also this ensures, that the latest security patches in PHP are installed. Therefore we recommend to use the latest image.
Go backend
A Go implementation is available in the speedtest-go repo, maintained by Maddie Zhan.
Rust backend
A Rust implementation is available in the speedtest-rust repo, maintained by Sudo Dios.
Node.js backend
A partial Node.js implementation is available in the node branch, developed by dunklesToast. It's not recommended to use at the moment.
Donate
License
Copyright (C) 2016-2024 Federico Dossena
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this program. If not, see https://www.gnu.org/licenses/lgpl.

