Have you ever wondered how stable your internet connection is throughout the day? Speed can drop in the evening or disappear for several minutes. In this article, we'll create a simple automated monitoring system. We'll use the professional tool Ookla Speedtest CLI, and visualize the data in convenient charts through the cloud service VizIoT.
Before writing code, let's prepare the "receiver" for our data.
The script is written in JavaScript and runs in the Node.js environment. Choose the instructions for your operating system:
node -v and npm -v.We recommend using the NVM version manager. Open a terminal and execute:
# 1. Download and install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
# 2. Activate nvm (for the current terminal session)
. "$HOME/.nvm/nvm.sh"
# 3. Install Node.js
nvm install 24
# 4. Verify installation
node -v
npm -v
Now let's prepare the working folder and download the necessary tools.
Create a project folder:
mkdir -p /var/viziot/speedtest
cd /var/viziot/speedtest
Initialize the project and install the VizIoT library:
npm init -y
npm install viziot-mqtt-client-nodejs
Download the Speedtest CLI client directly to the project folder: Choose the commands for your system:
Windows (PowerShell):
Invoke-WebRequest -Uri "https://install.speedtest.net/app/cli/ookla-speedtest-1.2.0-win64.zip" -OutFile "speedtest.zip"
Expand-Archive -Path "speedtest.zip" -DestinationPath "." -Force
macOS (Terminal):
curl -o speedtest.tgz https://install.speedtest.net/app/cli/ookla-speedtest-1.2.0-macosx-universal.tgz
tar -xzf speedtest.tgz
Linux (Terminal):
wget https://install.speedtest.net/app/cli/ookla-speedtest-1.2.0-linux-x86_64.tgz
tar -xzf ookla-speedtest-1.2.0-linux-x86_64.tgz
Create a main.js file and paste the code into it: (If you're on Linux, use nano main.js, on Windows — any text editor)
const os = require('os')
const { exec } = require('child_process')
const viziotMQTT = require('viziot-mqtt-client-nodejs')
// --- SETTINGS ---
// Insert your VizIoT device key and password here
let keyDevice = 'YOUR_ACCESS_KEY'
let passDevice = 'YOUR_ACCESS_PASSWORD'
const speedTestIntervalMinutes = 60 // How often to run the test (in minutes)
// -----------------
let viziotMQTTClient = new viziotMQTT(keyDevice, passDevice)
let idIntervalSpeedTest = null
function main() {
console.log('Starting... Connecting to VizIoT')
viziotMQTTClient.connect(() => {
console.log('Connection to server established!')
runSpeedTest()
// Start scheduled runs
clearInterval(idIntervalSpeedTest)
idIntervalSpeedTest = setInterval(runSpeedTest, speedTestIntervalMinutes * 60 * 1000)
})
}
function runSpeedTest() {
let command = ''
const flags = '--format=json --accept-license --accept-gdpr'
switch (os.platform()) {
case 'win32':
command = `.\\speedtest.exe ${flags}`
break
case 'linux':
command = `./speedtest ${flags}`
break
case 'darwin':
command = `./speedtest ${flags}`
break
}
console.log('Starting speed test...')
exec(command, (error, stdout) => {
if (error) {
console.log('Test execution error. Check if speedtest is installed and internet connection is available.')
const packet = {
upload: -500,
download: -500,
ping: -500,
packet_loss: -500,
jitter_upload: -500,
jitter_download: -500,
}
viziotMQTTClient.sendDataToVizIoT(packet, (err) => {
if (err) console.log('Send error:', err)
else console.log('Data successfully sent:', packet)
})
return
}
try {
const json = JSON.parse(stdout)
const packet = {
upload: ((json.upload.bandwidth * 8) / 1000000).toFixed(2), // Convert from bytes/s to megabits/s
download: ((json.download.bandwidth * 8) / 1000000).toFixed(2), // Convert from bytes/s to megabits/s
ping: json.ping.latency.toFixed(2),
packet_loss: json.packetLoss ? json.packetLoss.toFixed(2) : 0,
jitter_upload: json.upload.latency.jitter.toFixed(2),
jitter_download: json.download.latency.jitter.toFixed(2),
}
viziotMQTTClient.sendDataToVizIoT(packet, (err) => {
if (err) console.log('Error sending to VizIoT:', err)
else console.log('Data successfully sent:', packet)
})
} catch (err) {
console.log('JSON processing error:', err)
}
})
}
main()
Before leaving the script running in the background, we need to make sure it works correctly.
In the terminal (in the project folder), run the command:
node main.js
What should happen:
Connection to server established!.Starting speed test... (this may take 30-60 seconds).Data successfully sent: and an object with your speed metrics.If everything works — congratulations! The script is working. Press Ctrl + C to stop it.
To keep monitoring running 24/7 even after closing the terminal or rebooting the server, we'll use the PM2 process manager.
# 1. Install PM2 globally
npm install pm2 -g
# 2. Start your script under PM2 management
pm2 start main.js --name "viziot-speedtest"
# 3. Save the process list (so they start after reboot)
pm2 save
# 4. Configure autostart on system boot
pm2 startup
# After this command, PM2 will output a line that you need to copy and execute.
Now the script runs independently. You can check its status with the pm2 status command.
Return to VizIoT:
download).Repeat this for the upload and ping parameters. Now you'll visually see all speed drops in real time!
You can find detailed instructions for setting up charts in the article "Introduction to VizIoT".
We've created a reliable system that automatically checks internet quality. Using the official Ookla client, you get accurate data, while VizIoT handles history storage and chart rendering. No more verbal disputes with your ISP — you'll have clear evidence of connection quality!