Skip to main content

Using JSON output

To get speed test results in JSON format, use the -json flag:
unispeedtest -json
For formatted JSON with indentation:
unispeedtest -pretty
The -pretty flag automatically enables JSON output (it implies -json), so you don’t need both flags.

JSON schema

The JSON output follows this structure (actual field names from internal/reporter/printer.go:70-79):
{
  "download_mbps": 145.89,
  "upload_mbps": 95.67,
  "latency_ms": {
    "unloaded": 12.34,
    "loaded_down": 45.67,
    "loaded_up": 38.21,
    "jitter": 2.15
  },
  "packet_loss_percent": 0.3,
  "server_colo": "San Francisco",
  "network_asn": "AS12345",
  "network_as_org": "Example ISP",
  "ip": "203.0.113.42"
}

Field descriptions

download_mbps
float
Overall download speed in megabits per second (90th percentile of all samples)
upload_mbps
float
Overall upload speed in megabits per second (90th percentile of all samples)
latency_ms
object
Latency measurements in milliseconds
packet_loss_percent
float
Packet loss percentage (0-100), rounded to one decimal place. Measured from 1000 concurrent requests.
server_colo
string
Cloudflare data center city name used for testing
network_asn
string
Your network’s Autonomous System Number in “AS####” format
network_as_org
string
Your ISP or network organization name
ip
string
Your public IP address as detected by Cloudflare

Compact vs pretty output

Compact JSON (default with -json)

unispeedtest -json
Outputs a single line (example truncated for readability):
{"download_mbps":145.89,"upload_mbps":95.67,"latency_ms":{"unloaded":12.34,"loaded_down":45.67,"loaded_up":38.21,"jitter":2.15},"packet_loss_percent":0.3,"server_colo":"San Francisco","network_asn":"AS12345","network_as_org":"Example ISP","ip":"203.0.113.42"}
Best for: Piping to tools, logging, database storage, bandwidth-sensitive scenarios

Pretty-printed JSON (with -pretty)

unispeedtest -pretty
Outputs formatted JSON with 2-space indentation:
{
  "download_mbps": 145.89,
  "upload_mbps": 95.67,
  "latency_ms": {
    "unloaded": 12.34,
    "loaded_down": 45.67,
    "loaded_up": 38.21,
    "jitter": 2.15
  },
  "packet_loss_percent": 0.3,
  "server_colo": "San Francisco",
  "network_asn": "AS12345",
  "network_as_org": "Example ISP",
  "ip": "203.0.113.42"
}
Best for: Debugging, manual inspection, configuration files
The implementation uses Go’s json.Marshal() for compact output and json.MarshalIndent(data, "", " ") for pretty output. See internal/reporter/printer.go:82-110.

Automation examples

Piping to jq

Extract specific fields using jq:
# Get just the download speed
unispeedtest -json | jq '.download_mbps'

# Get both download and upload speeds
unispeedtest -json | jq '{download: .download_mbps, upload: .upload_mbps}'

# Check if packet loss is above 1%
unispeedtest -json | jq 'select(.packet_loss_percent > 1)'

# Get unloaded latency
unispeedtest -json | jq '.latency_ms.unloaded'

Saving to a file

Save results with timestamp:
# Compact JSON
unispeedtest -json > speedtest-$(date +%Y%m%d-%H%M%S).json

# Pretty-printed JSON
unispeedtest -pretty > speedtest-$(date +%Y%m%d-%H%M%S).json

Scheduled testing

Run periodic tests and append to a log file:
#!/bin/bash
# Run every hour via cron
timestamp=$(date -Iseconds)
result=$(unispeedtest -json)
echo "{\"timestamp\":\"$timestamp\",\"result\":$result}" >> /var/log/speedtest.jsonl
Add to crontab:
0 * * * * /path/to/speedtest-logger.sh

Conditional alerting

Alert if speeds drop below threshold:
#!/bin/bash
MIN_DOWNLOAD=50  # Minimum acceptable download speed in Mbps

result=$(unispeedtest -json)
download=$(echo "$result" | jq '.download_mbps')

if (( $(echo "$download < $MIN_DOWNLOAD" | bc -l) )); then
  echo "WARNING: Download speed ($download Mbps) below threshold ($MIN_DOWNLOAD Mbps)"
  # Send alert (email, Slack, etc.)
  echo "$result" | mail -s "Speed Test Alert" [email protected]
fi

Shell script with error handling

#!/bin/bash
set -euo pipefail

if ! result=$(unispeedtest -json 2>&1); then
  echo "Speed test failed: $result" >&2
  exit 1
fi

if ! echo "$result" | jq -e . >/dev/null 2>&1; then
  echo "Invalid JSON output" >&2
  exit 1
fi

# Process valid JSON
echo "$result" | jq '.'

Integration with monitoring systems

Prometheus

Use a textfile collector to expose metrics:
#!/bin/bash
# prometheus-speedtest.sh
OUTPUT_FILE="/var/lib/prometheus/node-exporter/speedtest.prom"

result=$(unispeedtest -json)

cat > "$OUTPUT_FILE" <<EOF
# HELP speedtest_download_mbps Download speed in megabits per second
# TYPE speedtest_download_mbps gauge
speedtest_download_mbps $(echo "$result" | jq -r '.download_mbps')

# HELP speedtest_upload_mbps Upload speed in megabits per second
# TYPE speedtest_upload_mbps gauge
speedtest_upload_mbps $(echo "$result" | jq -r '.upload_mbps')

# HELP speedtest_latency_ms Latency in milliseconds
# TYPE speedtest_latency_ms gauge
speedtest_latency_ms{type="unloaded"} $(echo "$result" | jq -r '.latency_ms.unloaded')
speedtest_latency_ms{type="loaded_down"} $(echo "$result" | jq -r '.latency_ms.loaded_down')
speedtest_latency_ms{type="loaded_up"} $(echo "$result" | jq -r '.latency_ms.loaded_up')
speedtest_latency_ms{type="jitter"} $(echo "$result" | jq -r '.latency_ms.jitter')

# HELP speedtest_packet_loss_percent Packet loss percentage
# TYPE speedtest_packet_loss_percent gauge
speedtest_packet_loss_percent $(echo "$result" | jq -r '.packet_loss_percent')
EOF

InfluxDB

Write results to InfluxDB:
#!/bin/bash
INFLUX_URL="http://localhost:8086"
INFLUX_TOKEN="your-token"
INFLUX_ORG="your-org"
INFLUX_BUCKET="speedtest"

result=$(unispeedtest -json)

# Convert to InfluxDB line protocol
timestamp=$(date +%s%N)
download=$(echo "$result" | jq -r '.download_mbps')
upload=$(echo "$result" | jq -r '.upload_mbps')
latency=$(echo "$result" | jq -r '.latency_ms.unloaded')
jitter=$(echo "$result" | jq -r '.latency_ms.jitter')
packet_loss=$(echo "$result" | jq -r '.packet_loss_percent')
server=$(echo "$result" | jq -r '.server_colo')

curl -XPOST "$INFLUX_URL/api/v2/write?org=$INFLUX_ORG&bucket=$INFLUX_BUCKET" \
  -H "Authorization: Token $INFLUX_TOKEN" \
  -H "Content-Type: text/plain; charset=utf-8" \
  --data-binary "speedtest,server=$server download=$download,upload=$upload,latency=$latency,jitter=$jitter,packet_loss=$packet_loss $timestamp"

Grafana Loki

Ship JSON logs to Loki:
#!/bin/bash
LOKI_URL="http://localhost:3100"

result=$(unispeedtest -json)
timestamp=$(date +%s%N)  # nanoseconds

# Send to Loki
curl -XPOST "$LOKI_URL/loki/api/v1/push" \
  -H "Content-Type: application/json" \
  --data-binary @- <<EOF
{
  "streams": [
    {
      "stream": {
        "job": "speedtest",
        "host": "$(hostname)"
      },
      "values": [
        ["$timestamp", $(echo "$result" | jq -c '.')]
      ]
    }
  ]
}
EOF

Error handling

When running in JSON mode, the tool will:
  1. Suppress progress output - No messages during testing
  2. Write errors to stderr - Error messages go to stderr, not stdout
  3. Exit with non-zero code - Returns exit code 1 on JSON encoding errors
Example error handling:
if result=$(unispeedtest -json 2>/tmp/error.log); then
  echo "Success: $result" | jq '.'
else
  echo "Failed. Check /tmp/error.log for details" >&2
  exit 1
fi
The tool may still print warnings to stderr even in JSON mode (e.g., “Warning: could not fetch network metadata”). Always redirect stderr if you need clean JSON output.

Best practices

Validate JSON

Always validate JSON output before processing:
result=$(unispeedtest -json)
echo "$result" | jq -e . > /dev/null

Use compact for logs

Use -json (not -pretty) when writing to log files or databases to save space.

Redirect stderr

Redirect stderr when you need clean JSON:
unispeedtest -json 2>/dev/null

Add timestamps

Always add timestamps when logging results for historical analysis.

Build docs developers (and LLMs) love