24/7 Internet Speed Monitoring: Building a System with Ookla Speedtest and VizIoT

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.


Step 1: Setting Up a Device in VizIoT

Before writing code, let's prepare the "receiver" for our data.

  1. Log into your VizIoT account.
  2. Create a new device named "SPEEDTEST".
  3. Add the following parameters to it (the script will write data to these):
    • download — Megabits per second (Mbps)
    • upload — Megabits per second (Mbps)
    • ping — Milliseconds (ms)
    • packet_loss — Percentage (%)
    • jitter_download — Milliseconds (ms)
    • jitter_upload — Milliseconds (ms)
  4. Go to the device's "Basic Settings" and make sure to save the Access Key and Access Password. You'll need them later.

Step 2: Installing Node.js

The script is written in JavaScript and runs in the Node.js environment. Choose the instructions for your operating system:

For Windows

  1. Go to the official Node.js website.
  2. Download the Prebuilt Node.js Windows Installer (.msi).
  3. Run the file and follow the installer instructions (just click "Next").
  4. After installation, open a terminal (CMD or PowerShell) and check the version with the commands node -v and npm -v.

For macOS and Ubuntu/Linux

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

Step 3: Project Setup and Speedtest CLI Installation

Now let's prepare the working folder and download the necessary tools.

  1. Create a project folder:

    mkdir -p /var/viziot/speedtest
    cd /var/viziot/speedtest
  2. Initialize the project and install the VizIoT library:

    npm init -y
    npm install viziot-mqtt-client-nodejs
  3. 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
  4. 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()

Step 4: Manual Launch and Testing

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:

  1. The console should display: Connection to server established!.
  2. Then: Starting speed test... (this may take 30-60 seconds).
  3. Finally, you'll see: Data successfully sent: and an object with your speed metrics.

If everything works — congratulations! The script is working. Press Ctrl + C to stop it.


Step 5: Setting Up Autonomous Operation (PM2)

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.


Step 6: Visualization (Beautiful Charts)

Return to VizIoT:

  1. Create a new dashboard.
  2. Add a "Chart" widget.
  3. In the widget settings, link your SPEEDTEST device to the widget and select the desired parameter (for example, download).
  4. Configure the display period (for example, the last 24 hours).

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".


Conclusion

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!