SpeedOf.Me API - Vanilla JavaScript

Vanilla JavaScript is the simplest way to integrate the SpeedOf.Me speed test API. No frameworks or build tools required.

Quick Start

1. Include the API Script

<script src="https://speedof.me/api/api.js"></script>

2. Configure and Start

// Required configuration
SomApi.account = "YOUR_API_KEY";
SomApi.domainName = "your-domain.com";

// Callbacks
SomApi.onTestCompleted = function(result) {
    console.log('Download:', result.download, 'Mbps');
    console.log('Upload:', result.upload, 'Mbps');
    console.log('Latency:', result.latency, 'ms');
};

SomApi.onError = function(error) {
    console.error('Error:', error.code, error.message);
};

// Start test
SomApi.startTest();

Configuration Options

// Test behavior
SomApi.config.sustainTime = 6;           // 1-8 seconds (higher = more accurate)
SomApi.config.testServerEnabled = true;  // Include server location
SomApi.config.userInfoEnabled = true;    // Include IP/hostname
SomApi.config.latencyTestEnabled = true; // Run latency test
SomApi.config.uploadTestEnabled = true;  // Run upload test

// Progress updates
SomApi.config.progress.enabled = true;   // Enable progress callbacks
SomApi.config.progress.verbose = true;   // Detailed progress data

Callbacks Reference

onTestCompleted(result)

SomApi.onTestCompleted = function(result) {
    result.download;    // Download speed in Mbps
    result.upload;      // Upload speed in Mbps
    result.latency;     // Latency in ms
    result.jitter;      // Jitter in ms
    result.testServer;  // Server location code
    result.ip_address;  // Client IP address
    result.hostname;    // Client hostname
};

onProgress(progress)

SomApi.onProgress = function(progress) {
    progress.type;         // 'download' or 'upload'
    progress.currentSpeed; // Current speed in Mbps
    progress.percentDone;  // 0-100
    progress.pass;         // Current test pass number
};

onError(error)

SomApi.onError = function(error) {
    error.code;    // 1001 = invalid account, 1002 = domain mismatch
    error.message; // Human-readable message
};

Complete Example - Basic

Minimal implementation with start button and results display:

<!DOCTYPE html>
<html>
<head>
    <title>Speed Test</title>
    <script src="https://speedof.me/api/api.js"></script>
    <style>
        body { font-family: sans-serif; max-width: 400px; margin: 50px auto; text-align: center; }
        button { padding: 15px 40px; font-size: 18px; cursor: pointer; }
        #results { margin-top: 20px; font-size: 18px; }
    </style>
</head>
<body>
    <h1>Speed Test</h1>
    <button onclick="startTest()">Start Test</button>
    <div id="results"></div>

    <script>
        SomApi.account = "YOUR_API_KEY";
        SomApi.domainName = "your-domain.com";

        SomApi.onTestCompleted = function(r) {
            document.getElementById('results').innerHTML =
                'Download: ' + r.download + ' Mbps<br>' +
                'Upload: ' + r.upload + ' Mbps<br>' +
                'Latency: ' + r.latency + ' ms';
        };

        SomApi.onError = function(e) {
            document.getElementById('results').innerHTML = 'Error: ' + e.message;
        };

        function startTest() {
            document.getElementById('results').innerHTML = 'Testing...';
            SomApi.startTest();
        }
    </script>
</body>
</html>

Complete Example - Advanced with UI

Full-featured implementation with Bootstrap 5, settings panel, progress bar, and styled results. Copy and paste this entire file:

Tip: Replace YOUR_API_KEY and your-domain.com with your credentials from the API Portal.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Speed Test - Advanced</title>

    <!-- Bootstrap 5 CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.2/font/bootstrap-icons.css" rel="stylesheet">

    <!-- SpeedOf.Me API -->
    <script src="https://speedof.me/api/api.js"></script>

    <style>
        body {
            background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
            min-height: 100vh;
            color: #fff;
        }
        .card {
            background: rgba(255, 255, 255, 0.95);
            border: none;
            border-radius: 1rem;
            box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
        }
        .settings-card {
            background: #f8f9fa;
            border-radius: 0.75rem;
        }
        .result-card {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: #fff;
        }
        .speed-value {
            font-size: 2.5rem;
            font-weight: 700;
            line-height: 1;
        }
        .speed-unit {
            font-size: 0.9rem;
            opacity: 0.8;
        }
        .btn-start {
            background: linear-gradient(135deg, #00d4ff 0%, #090979 100%);
            border: none;
            padding: 0.875rem 2.5rem;
            font-size: 1.1rem;
            font-weight: 600;
            border-radius: 50px;
            transition: transform 0.2s, box-shadow 0.2s;
        }
        .btn-start:hover:not(:disabled) {
            transform: translateY(-2px);
            box-shadow: 0 8px 25px rgba(0, 212, 255, 0.4);
        }
        .btn-start:disabled { opacity: 0.6; }
        .progress-section {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            border-radius: 0.75rem;
            color: #fff;
        }
        .progress-bar-custom {
            height: 8px;
            border-radius: 4px;
            background: rgba(255,255,255,0.2);
            overflow: hidden;
        }
        .progress-bar-fill {
            height: 100%;
            background: #fff;
            border-radius: 4px;
            transition: width 0.3s ease;
        }
        .form-check-input:checked {
            background-color: #667eea;
            border-color: #667eea;
        }
        .live-speed {
            font-size: 3rem;
            font-weight: 700;
        }
    </style>
</head>
<body>
    <div class="container py-5">
        <!-- Header -->
        <div class="text-center mb-4">
            <h1 class="display-5 fw-bold mb-2">
                <i class="bi bi-speedometer2 me-2"></i>Speed Test
            </h1>
        </div>

        <div class="row justify-content-center">
            <div class="col-lg-10">
                <div class="card">
                    <div class="card-body p-4">
                        <div class="row">
                            <!-- Settings Column -->
                            <div class="col-lg-4 mb-4 mb-lg-0">
                                <div class="settings-card p-3">
                                    <h5 class="mb-3">
                                        <i class="bi bi-sliders me-2"></i>Settings
                                    </h5>

                                    <!-- Sustain Time -->
                                    <div class="mb-4">
                                        <label class="form-label d-flex justify-content-between">
                                            <span>Sustain Time</span>
                                            <span class="badge bg-primary" id="sustainTimeValue">6</span>
                                        </label>
                                        <div class="d-flex align-items-center">
                                            <small class="text-muted me-2">Fast</small>
                                            <input type="range" class="form-range flex-grow-1" id="sustainTime"
                                                   min="1" max="8" value="6" oninput="updateSustainTime()">
                                            <small class="text-muted ms-2">Accurate</small>
                                        </div>
                                    </div>

                                    <!-- Options -->
                                    <div class="mb-3">
                                        <div class="form-check mb-2">
                                            <input class="form-check-input" type="checkbox" id="latencyTest" checked>
                                            <label class="form-check-label" for="latencyTest">
                                                <i class="bi bi-clock me-1"></i>Latency Test
                                            </label>
                                        </div>
                                        <div class="form-check mb-2">
                                            <input class="form-check-input" type="checkbox" id="uploadTest" checked>
                                            <label class="form-check-label" for="uploadTest">
                                                <i class="bi bi-arrow-up me-1"></i>Upload Test
                                            </label>
                                        </div>
                                    </div>

                                    <!-- Start Button -->
                                    <div class="d-grid mt-4">
                                        <button id="btnStart" class="btn btn-primary btn-start" onclick="startTest()">
                                            <i class="bi bi-play-fill me-2"></i>Start Test
                                        </button>
                                    </div>
                                </div>
                            </div>

                            <!-- Results Column -->
                            <div class="col-lg-8">
                                <!-- Initial State -->
                                <div id="initialState" class="text-center py-5">
                                    <i class="bi bi-speedometer2 text-muted" style="font-size: 4rem;"></i>
                                    <h4 class="text-muted mt-3">Ready to Test</h4>
                                    <p class="text-muted">Click Start Test to begin</p>
                                </div>

                                <!-- Progress State -->
                                <div id="progressState" style="display: none;">
                                    <div class="progress-section p-4 mb-4">
                                        <div class="text-center mb-3">
                                            <div class="text-uppercase small opacity-75" id="progressType">Initializing</div>
                                            <div class="live-speed" id="liveSpeed">--</div>
                                            <div class="small opacity-75">Mbps</div>
                                        </div>
                                        <div class="progress-bar-custom">
                                            <div class="progress-bar-fill" id="progressBar" style="width: 0%"></div>
                                        </div>
                                        <div class="text-center mt-2 small opacity-75" id="progressPercent">0%</div>
                                    </div>
                                </div>

                                <!-- Results State -->
                                <div id="resultsState" style="display: none;">
                                    <div class="row g-3 mb-4">
                                        <div class="col-6">
                                            <div class="card result-card h-100">
                                                <div class="card-body text-center py-4">
                                                    <i class="bi bi-arrow-down-circle"></i>
                                                    <div class="speed-value mt-2" id="downloadSpeed">--</div>
                                                    <div class="speed-unit">Mbps Download</div>
                                                </div>
                                            </div>
                                        </div>
                                        <div class="col-6">
                                            <div class="card result-card h-100">
                                                <div class="card-body text-center py-4">
                                                    <i class="bi bi-arrow-up-circle"></i>
                                                    <div class="speed-value mt-2" id="uploadSpeed">--</div>
                                                    <div class="speed-unit">Mbps Upload</div>
                                                </div>
                                            </div>
                                        </div>
                                        <div class="col-6">
                                            <div class="card bg-light h-100">
                                                <div class="card-body text-center py-3">
                                                    <i class="bi bi-clock text-primary"></i>
                                                    <div class="fs-3 fw-bold text-dark mt-2" id="latency">--</div>
                                                    <div class="text-muted small">ms Latency</div>
                                                </div>
                                            </div>
                                        </div>
                                        <div class="col-6">
                                            <div class="card bg-light h-100">
                                                <div class="card-body text-center py-3">
                                                    <i class="bi bi-activity text-primary"></i>
                                                    <div class="fs-3 fw-bold text-dark mt-2" id="jitter">--</div>
                                                    <div class="text-muted small">ms Jitter</div>
                                                </div>
                                            </div>
                                        </div>
                                    </div>

                                    <!-- Additional Info -->
                                    <div class="p-3 bg-light rounded">
                                        <div class="row text-center g-2">
                                            <div class="col-md-4">
                                                <small class="text-muted d-block">Test Server</small>
                                                <span class="fw-semibold text-dark small" id="testServer">--</span>
                                            </div>
                                            <div class="col-md-4">
                                                <small class="text-muted d-block">Your IP</small>
                                                <span class="fw-semibold text-dark small" id="ipAddress">--</span>
                                            </div>
                                            <div class="col-md-4">
                                                <small class="text-muted d-block">Hostname</small>
                                                <span class="fw-semibold text-dark small" id="hostname">--</span>
                                            </div>
                                        </div>
                                    </div>
                                </div>

                                <!-- Error State -->
                                <div id="errorState" style="display: none;">
                                    <div class="alert alert-danger text-center">
                                        <i class="bi bi-exclamation-triangle-fill me-2"></i>
                                        <span id="errorMessage">An error occurred</span>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        // ========================================
        // SpeedOf.Me API Configuration
        // ========================================
        SomApi.account = "YOUR_API_KEY";         // Replace with your API key
        SomApi.domainName = "your-domain.com";   // Replace with your domain

        // Callbacks
        SomApi.onTestCompleted = onTestCompleted;
        SomApi.onError = onError;
        SomApi.onProgress = onProgress;

        // Enable progress
        SomApi.config.progress.enabled = true;
        SomApi.config.progress.verbose = true;

        // ========================================
        // UI Functions
        // ========================================
        function updateSustainTime() {
            var value = document.getElementById('sustainTime').value;
            document.getElementById('sustainTimeValue').textContent = value;
        }

        function startTest() {
            // Apply settings from UI
            SomApi.config.sustainTime = document.getElementById('sustainTime').value;
            SomApi.config.latencyTestEnabled = document.getElementById('latencyTest').checked;
            SomApi.config.uploadTestEnabled = document.getElementById('uploadTest').checked;

            // Update UI
            document.getElementById('initialState').style.display = 'none';
            document.getElementById('progressState').style.display = 'none';
            document.getElementById('resultsState').style.display = 'none';
            document.getElementById('errorState').style.display = 'none';
            document.getElementById('btnStart').disabled = true;
            document.getElementById('btnStart').innerHTML =
                '<span class="spinner-border spinner-border-sm me-2"></span>Testing...';

            SomApi.startTest();
        }

        function onProgress(progress) {
            var type = (progress.type || '').toLowerCase();

            // Show progress during download/upload
            if (type.includes('download') || type.includes('upload')) {
                document.getElementById('progressState').style.display = 'block';
                document.getElementById('progressType').textContent = progress.type;
                document.getElementById('liveSpeed').textContent = progress.currentSpeed || '--';
                document.getElementById('progressBar').style.width = progress.percentDone + '%';
                document.getElementById('progressPercent').textContent = progress.percentDone + '%';
            }
        }

        function onTestCompleted(result) {
            document.getElementById('progressState').style.display = 'none';
            document.getElementById('resultsState').style.display = 'block';

            document.getElementById('downloadSpeed').textContent = result.download || '--';
            document.getElementById('uploadSpeed').textContent = result.upload || '--';
            document.getElementById('latency').textContent = result.latency || '--';
            document.getElementById('jitter').textContent = result.jitter || '--';
            document.getElementById('testServer').textContent = result.testServer || '--';
            document.getElementById('ipAddress').textContent = result.ip_address || '--';
            document.getElementById('hostname').textContent = result.hostname || '--';

            resetButton();
        }

        function onError(error) {
            document.getElementById('progressState').style.display = 'none';
            document.getElementById('errorState').style.display = 'block';
            document.getElementById('errorMessage').textContent =
                'Error ' + error.code + ': ' + error.message;
            resetButton();
        }

        function resetButton() {
            document.getElementById('btnStart').disabled = false;
            document.getElementById('btnStart').innerHTML =
                '<i class="bi bi-arrow-clockwise me-2"></i>Test Again';
        }
    </script>

    <!-- Bootstrap JS -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

Links