SpeedOf.Me API - React Native Integration

This example demonstrates how to integrate the SpeedOf.Me speed test API into a React Native app using react-native-webview.

How It Works

The SpeedOf.Me API is JavaScript-based, so React Native apps use WebView to:

  1. Load an HTML page containing the speed test
  2. Receive results via the onMessage prop

Files

Prerequisites

Quick Start

1. Install react-native-webview

npm install react-native-webview

# For iOS
cd ios && pod install

2. Configure API Credentials

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

3. Host speedtest.html on Your Registered Domain

Upload speedtest.html to the domain registered on your account and point the WebView at that URL:

const webViewSource = { uri: 'https://your-domain.com/speedtest.html' };

It has to be a remote http(s) URL. The engine validates the page that embeds api.js against the domain registered on your account, and it reads that from the page's own URL. A page with no host can never match, so every test fails with error 1002 (Domain Mismatch). That rules out an inline html source (which loads as about:blank) and a file:///android_asset/ asset: neither is a usable loading method for this API.

Architecture

React Native App
   └── SpeedTestScreen
           └── WebView (react-native-webview)
                   └── speedtest.html
                           └── api.js (defines the SomApi global)
                                   ▼
                   window.ReactNativeWebView.postMessage(json)
                                   ▼
                   onMessage={(event) => {...}}

JavaScript-to-React-Native Communication

The HTML page sends messages via:

window.ReactNativeWebView.postMessage(JSON.stringify({
    type: 'completed',
    data: result
}));

React Native receives them:

<WebView
    onMessage={(event) => {
        const message = JSON.parse(event.nativeEvent.data);
        // Handle message
    }}
/>

What the Engine Sends

speedtest.html normalizes the engine's payloads before forwarding them, so the React Native side always receives numbers. This is what the raw callbacks give you inside the page.

onProgress(progress):

speedtest.html sets SomApi.config.progress.verbose = true, which is what fills in currentSpeed. Without it that field is '' on every event.

onTestCompleted(result) always carries every field. A disabled sub-test sends an empty string rather than omitting the key: download, upload, maxDownload, maxUpload, latency, jitter, testServer, ip_address, hostname, userAgent, testDate. upload and maxUpload are '' when uploadTestEnabled is false, latency and jitter are '' when latencyTestEnabled is false, testServer is '' when testServerEnabled is false, and ip_address is '0.0.0.0' with hostname '' when userInfoEnabled is false. Those empty strings are why the page normalizes before forwarding.

TypeScript Types

These describe the normalized payloads the WebView forwards, which is what SpeedTestScreen.tsx consumes:

interface SpeedTestResult {
    download: number;
    upload: number;
    latency: number;
    jitter: number;
    testServer: string;
    ip_address: string;
    hostname: string;
}

interface SpeedTestProgress {
    type: 'download' | 'upload' | 'latency';
    currentSpeed: number; // Mbps, 0 on latency events
    percentDone: number;
    pass: number; // 0 during the latency phase
}

interface SpeedTestError {
    code: number;
    message: string;
}

Error Codes

1002 almost always means the page is not being served from your registered domain. 2006, and 2005 with status 0, mean the request never left the device, usually an ad blocker, a content blocker or a frame-src Content Security Policy that does not allow https://speedof.me. A 2005 carrying any other status is a real HTTP response: the request reached the network and came back refused.

Configuration Options

Customize in speedtest.html:

SomApi.config.sustainTime = 6;           // 1-8 seconds
SomApi.config.testServerEnabled = true;
SomApi.config.userInfoEnabled = true;
SomApi.config.latencyTestEnabled = true;
SomApi.config.uploadTestEnabled = true;
SomApi.config.progress.enabled = true;
SomApi.config.progress.verbose = true;   // required for progress.currentSpeed

Expo Support

npx expo install react-native-webview

Production Considerations

  1. API Key Security: Store keys in environment variables
  2. Network State: Check connectivity before starting test
  3. Background Handling: Speed tests should run in foreground only
  4. Data Usage Warning: Warn users on cellular connections

Troubleshooting

Links