speed test use html, js, cs, inline code
Here’s a single-file, copy-pasteable speed-test page using only HTML + inline CSS + vanilla JS. It measures latency (ping), download, and upload, shows your public IP, and works without any external libraries.
Tip: It tries Cloudflare’s public speed endpoint for download and httpbin for upload. If your hosting blocks cross-origin requests, set
CUSTOM_DOWNLOAD_URLin the code to a file on your own server (e.g., a 50–200 MB file).
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Simple Speed Test</title>
<style>
:root{
--bg:#0b0f14; --panel:#111826; --muted:#8aa0b2; --text:#e8f1f8; --accent:#4cc9f0; --ok:#22c55e; --warn:#fbbf24; --err:#ef4444;
}
*{box-sizing:border-box}
body{
margin:0; font-family:system-ui,Segoe UI,Roboto,Inter,Arial,sans-serif;
background: radial-gradient(1200px 800px at 80% -20%, #0f172a 0%, #0b0f14 40%, #070b10 100%);
color:var(--text);
}
.wrapper{
max-width:980px; margin:40px auto; padding:20px;
}
h1{margin:0 0 6px; font-size:28px; font-weight:800; letter-spacing:.2px}
p.subtitle{margin:0 0 20px; color:var(--muted)}
.grid{display:grid; gap:16px; grid-template-columns:repeat(12,1fr)}
.card{
grid-column: span 12;
background:linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,255,255,.02));
border:1px solid rgba(255,255,255,.06);
border-radius:18px; padding:18px;
box-shadow: 0 10px 35px rgba(0,0,0,.35);
}
@media(min-width:760px){
.span-4{grid-column: span 4;}
.span-6{grid-column: span 6;}
.span-8{grid-column: span 8;}
.span-12{grid-column: span 12;}
}
.kpi{display:flex; align-items:baseline; gap:10px}
.kpi .value{font-size:42px; font-weight:900}
.kpi .unit{font-size:14px; color:var(--muted)}
.row{display:flex; gap:10px; flex-wrap:wrap; align-items:center}
button{
background:var(--accent); color:#001018; border:0; padding:12px 18px;
border-radius:12px; font-weight:800; cursor:pointer; transition:transform .08s ease;
}
button.secondary{background:transparent; color:var(--text); border:1px solid rgba(255,255,255,.18)}
button:active{transform:translateY(1px)}
.progress{
width:100%; height:10px; border-radius:999px; background:#0d1420; overflow:hidden; border:1px solid rgba(255,255,255,.08)
}
.bar{height:100%; width:0%; background:linear-gradient(90deg, #4cc9f0, #22d3ee, #0ea5e9); transition:width .2s ease}
.muted{color:var(--muted)}
.status{font-size:14px}
.badge{
display:inline-flex; align-items:center; gap:8px; padding:8px 10px; border-radius:999px;
background:rgba(255,255,255,.06); border:1px solid rgba(255,255,255,.1); color:var(--muted)
}
code.inline{background:#0d1420; padding:2px 6px; border-radius:6px; border:1px solid rgba(255,255,255,.06)}
.footer{margin-top:20px; font-size:12px; color:var(--muted)}
.small{font-size:12px}
</style>
</head>
<body>
<div class="wrapper">
<h1>Speed Test</h1>
<p class="subtitle">Lightweight HTML + JS speed test (no libs). Measures ping, download, and upload.</p>
<div class="grid">
<div class="card span-12">
<div class="row" style="justify-content:space-between">
<div class="row">
<button id="btnStart">Start Test</button>
<button id="btnStop" class="secondary">Stop</button>
</div>
<div id="badgeIP" class="badge">IP: <span id="ip">—</span></div>
</div>
<div class="row" style="margin-top:10px">
<span class="badge">Server: <span id="server">Auto</span></span>
<span class="badge">Location: <span id="loc">—</span></span>
</div>
</div>
<div class="card span-4">
<div class="kpi"><span class="value" id="latVal">—</span><span class="unit">ms</span></div>
<div class="muted small">Latency (avg of 5 pings)</div>
</div>
<div class="card span-4">
<div class="kpi"><span class="value" id="downVal">—</span><span class="unit">Mbps</span></div>
<div class="progress" style="margin-top:10px"><div class="bar" id="downBar"></div></div>
<div class="row" style="justify-content:space-between; margin-top:8px">
<span class="muted small">Download</span>
<span class="status small" id="downStatus">Idle</span>
</div>
</div>
<div class="card span-4">
<div class="kpi"><span class="value" id="upVal">—</span><span class="unit">Mbps</span></div>
<div class="progress" style="margin-top:10px"><div class="bar" id="upBar"></div></div>
<div class="row" style="justify-content:space-between; margin-top:8px">
<span class="muted small">Upload</span>
<span class="status small" id="upStatus">Idle</span>
</div>
</div>
<div class="card span-12">
<div class="row" style="justify-content:space-between; gap:8px">
<div class="muted small">
If remote servers block CORS, host a large file yourself and set
<code class="inline">CUSTOM_DOWNLOAD_URL</code> below.
</div>
<div class="row">
<button id="btnQuick5" class="secondary small">Quick Test</button>
<button id="btnFull" class="secondary small">Full Test</button>
</div>
</div>
<pre id="log" class="small" style="margin-top:10px; max-height:240px; overflow:auto; background:#0d1420; border:1px solid rgba(255,255,255,.06); border-radius:12px; padding:12px;"></pre>
</div>
</div>
<div class="footer">
Uses: Cloudflare <code class="inline">__down</code> for download, httpbin for upload, and <code class="inline">generate_204</code> for ping.
Replace endpoints if needed. Results may be influenced by browser & Wi-Fi.
</div>
</div>
<script>
(() => {
// ================== CONFIG ==================
// If CORS blocks the download test, put your own large file URL here:
const CUSTOM_DOWNLOAD_URL = ""; // e.g., "https://yourdomain.com/test/100mb.bin"
// Default endpoints
const PING_URL = "https://www.google.com/generate_204"; // no-cors ok for timing
const DOWN_URL = CUSTOM_DOWNLOAD_URL || "https://speed.cloudflare.com/__down?bytes=25000000"; // ~25 MB
const UP_POST = "https://httpbin.org/post"; // supports CORS
const DOWN_TARGET_BYTES = 25_000_000; // only used for progress % if server doesn't expose length
// ============================================
const $ = sel => document.querySelector(sel);
const fmt = (n, d=2) => Number.isFinite(n) ? n.toFixed(d) : "—";
const log = (msg) => {
const el = $("#log");
const time = new Date().toLocaleTimeString();
el.textContent += `[${time}] ${msg}\n`;
el.scrollTop = el.scrollHeight;
};
// UI elements
const latVal = $("#latVal");
const downVal = $("#downVal");
const upVal = $("#upVal");
const downBar = $("#downBar");
const upBar = $("#upBar");
const downStatus = $("#downStatus");
const upStatus = $("#upStatus");
const serverSpan = $("#server");
// State / cancellation
let aborters = [];
const makeAborter = () => {
const c = new AbortController();
aborters.push(c);
return c;
};
const cancelAll = () => {
aborters.forEach(a => a.abort());
aborters = [];
downStatus.textContent = "Canceled";
upStatus.textContent = "Canceled";
};
// IP + location
(async () => {
try {
const ipRes = await fetch("https://api.ipify.org?format=json", {cache:"no-store"});
const {ip} = await ipRes.json();
$("#ip").textContent = ip || "—";
} catch {}
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
pos => {
const {latitude, longitude} = pos.coords;
$("#loc").textContent = `${latitude.toFixed(3)}, ${longitude.toFixed(3)}`;
},
() => { $("#loc").textContent = "Permission denied"; },
{enableHighAccuracy:false, timeout:5000}
);
} else {
$("#loc").textContent = "Unavailable";
}
})();
// Latency test: do multiple pings and average
async function testLatency(samples=5) {
const times = [];
for (let i=0;i<samples;i++){
const s = performance.now();
try {
// Use no-cors so any 204/opaque is fine; we only care about timing
await fetch(PING_URL, { mode:"no-cors", cache:"no-store", signal: makeAborter().signal });
const e = performance.now();
times.push(e - s);
log(`Ping #${i+1}: ${fmt(e-s,1)} ms`);
await new Promise(r => setTimeout(r, 150));
} catch (err) {
if (err.name === "AbortError") throw err;
log(`Ping error: ${err.message || err}`);
}
}
times.sort((a,b)=>a-b);
const avg = times.reduce((a,b)=>a+b,0)/times.length || NaN;
latVal.textContent = fmt(avg,1);
return avg;
}
// Download test: stream a large response and measure throughput
async function testDownload(secondsCap=12) {
serverSpan.textContent = new URL(DOWN_URL).host;
downStatus.textContent = "Starting…";
downBar.style.width = "0%";
const start = performance.now();
let bytes = 0;
let lastTick = start;
let lastBytes = 0;
try {
const ctrl = makeAborter();
const res = await fetch(DOWN_URL, { cache:"no-store", signal: ctrl.signal });
const reader = res.body?.getReader?.();
const contentLen = Number(res.headers.get("content-length")) || DOWN_TARGET_BYTES;
if (!reader) {
// fallback: try to read as blob (may pause UI, but works)
const buf = await res.arrayBuffer();
bytes = buf.byteLength;
} else {
downStatus.textContent = "Measuring…";
while (true) {
const {done, value} = await reader.read();
if (done) break;
bytes += value.byteLength;
const now = performance.now();
// Update progress bar
const pct = Math.min(100, (bytes / contentLen) * 100);
downBar.style.width = pct + "%";
// Cap duration to avoid huge downloads
if ((now - start) / 1000 > secondsCap) {
ctrl.abort();
break;
}
// Smooth live Mbps
if (now - lastTick > 300) {
const deltaBytes = bytes - lastBytes;
const deltaSec = (now - lastTick)/1000;
const mbpsLive = (deltaBytes * 8) / (1e6 * deltaSec);
downVal.textContent = fmt(mbpsLive,1);
lastTick = now; lastBytes = bytes;
}
}
}
const durSec = (performance.now() - start)/1000;
const mbps = (bytes * 8) / (1e6 * durSec);
downVal.textContent = fmt(mbps,2);
downBar.style.width = "100%";
downStatus.textContent = `Done • ${fmt(bytes/1e6,1)} MB in ${fmt(durSec,1)} s`;
log(`Download: ${fmt(mbps,2)} Mbps (${fmt(bytes/1e6,1)} MB in ${fmt(durSec,1)} s)`);
return mbps;
} catch (err) {
if (err.name === "AbortError") { log("Download aborted."); return NaN; }
downStatus.textContent = "Failed";
log(`Download error: ${err.message || err}`);
return NaN;
}
}
// Upload test: POST random blob to an echo endpoint and time it
async function testUpload(sizeMB=10) {
upStatus.textContent = "Preparing…";
upBar.style.width = "0%";
const sizeBytes = sizeMB * 1024 * 1024;
// Create a deterministic blob without extra memory spikes by chunking
const chunkSize = 1024 * 1024; // 1MB chunks
const chunks = Math.ceil(sizeBytes / chunkSize);
const parts = [];
for (let i=0;i<chunks;i++){
const len = Math.min(chunkSize, sizeBytes - i*chunkSize);
parts.push(new Uint8Array(len)); // zeros are fine
const pct = Math.round(((i+1)/chunks)*100);
upBar.style.width = pct + "%";
// Yield UI
await new Promise(r => setTimeout(r, 0));
}
const blob = new Blob(parts, {type:"application/octet-stream"});
try {
upStatus.textContent = "Uploading…";
const start = performance.now();
const ctrl = makeAborter();
const res = await fetch(UP_POST, {
method:"POST",
body: blob,
signal: ctrl.signal,
});
const end = performance.now();
const durSec = (end - start)/1000;
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const mbps = (sizeBytes * 8) / (1e6 * durSec);
upVal.textContent = fmt(mbps,2);
upBar.style.width = "100%";
upStatus.textContent = `Done • ${sizeMB} MB in ${fmt(durSec,1)} s`;
log(`Upload: ${fmt(mbps,2)} Mbps (${sizeMB} MB in ${fmt(durSec,1)} s)`);
return mbps;
} catch (err) {
if (err.name === "AbortError") { log("Upload aborted."); return NaN; }
upStatus.textContent = "Failed";
log(`Upload error: ${err.message || err}`);
return NaN;
}
}
// Orchestrators
async function quickTest(){
disableButtons(true);
log("=== Quick Test (Ping + 10s Download + 5MB Upload) ===");
try {
await testLatency(5);
await testDownload(10);
await testUpload(5);
} catch (e) {
if (e.name !== "AbortError") log("Quick test stopped.");
} finally {
disableButtons(false);
}
}
async function fullTest(){
disableButtons(true);
log("=== Full Test (Ping + 12s Download + 10MB Upload) ===");
try {
await testLatency(7);
await testDownload(12);
await testUpload(10);
} catch (e) {
if (e.name !== "AbortError") log("Full test stopped.");
} finally {
disableButtons(false);
}
}
function disableButtons(disabled){
$("#btnStart").disabled = disabled;
$("#btnQuick5").disabled = disabled;
$("#btnFull").disabled = disabled;
$("#btnStop").disabled = !disabled;
}
// Wire up buttons
$("#btnStart").addEventListener("click", fullTest);
$("#btnFull").addEventListener("click", fullTest);
$("#btnQuick5").addEventListener("click", quickTest);
$("#btnStop").addEventListener("click", () => {
cancelAll();
disableButtons(false);
});
// Initial server label
serverSpan.textContent = (CUSTOM_DOWNLOAD_URL ? new URL(CUSTOM_DOWNLOAD_URL).host : new URL(DOWN_URL).host);
})();
</script>
</body>
</html>

Comments
Post a Comment