Originally published on KeyboardTester.click. This developer-focused adaptation was prepared for the site owner using AI agents, with facts checked against the source guide, current tool implementation and referenced documentation. The Python example was checked with synthetic exported observations; it is not a claim of a measured outage or a physical network diagnosis.
Photo: Helena Lopes / Pexels.
An application freezes for five seconds. By the time you open a speed test, everything works. Reinstalling the app and restarting the router both change the environment, but neither tells you which layer failed.
A better debugging artifact is a small incident record: the observed symptom, a bounded request log, a controlled comparison, and a clear statement of what those observations cannot establish.
Define what you are measuring
A browser-based HTTPS probe observes a complete application request to one endpoint. That path includes the browser, local connection, routing, the remote service and its response validation. It is useful evidence, but it is not an ICMP ping and its failed-request percentage is not a measured packet-loss percentage.
Likewise, a successful request to one server does not prove that a different meeting service or game route was healthy. A clean log may also miss a short failure between samples.
The Internet Stability Test makes repeated HTTPS requests to KeyboardTester.click, displays their timings and exports the observations as JSON. Its intended request-start interval is two seconds, with a five-second timeout; a longer request delays the next one. Hiding the tab stops the run and aborts its pending request. Keep the tab visible, record the actual duration and start a new run after an interruption.
These details matter when you compare two files. A short foreground session and a ten-minute session are different observation windows.
Change one variable at a time
Use a matrix rather than a sequence of unrelated fixes:
| Run | Keep fixed | Change | What a repeatable difference suggests |
|---|---|---|---|
| A versus B | Device, endpoint, VPN state and approximate load | Wi-Fi versus Ethernet | Investigate the wireless path if only the Wi-Fi run fails |
| B versus C | Wired device and endpoint | Quiet network versus ordinary upload load | Investigate contention or queueing if delay rises under load |
| B versus D | Connection and endpoint | One device versus another | Investigate the affected device's local configuration |
| B versus E | Device, connection and endpoint | VPN enabled versus disabled, where permitted | Investigate the VPN-dependent route if results differ |
Repeat a comparison before treating one good or bad run as a pattern. An Ethernet failure still leaves several candidates: cable, router, modem, device, upstream path or the test endpoint. It does not identify the ISP by itself.
Avoid changing firmware, DNS, channel, driver and VPN settings together. You may improve the symptom while destroying the evidence about which change helped.
Summarize the export locally
The tool's export contains a requests list with ok, at and timing fields. This small analyzer groups consecutive failed observations, which makes a long JSON file easier to discuss. It does not send the file anywhere.
Save the following as summarize_requests.py:
import json import sys from pathlib import Path def summarize_requests(rows): runs = [] current = [] failed = 0 def describe(run): return { "first_failed_sample": run[0], "last_failed_sample": run[-1], "failed_samples": len(run), } for row in rows: if not isinstance(row.get("ok"), bool): raise ValueError("Every observation needs a boolean ok field") if not isinstance(row.get("at"), str) or not row["at"]: raise ValueError("Every observation needs its recorded timestamp") if not row["ok"]: failed += 1 current.append(row["at"]) elif current: runs.append(describe(current)) current = [] if current: runs.append(describe(current)) return { "observations": len(rows), "failed_requests": failed, "failed_request_fraction": failed / len(rows) if rows else 0, "consecutive_failed_observation_runs": runs, } if __name__ == "__main__": exported = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8")) print(json.dumps(summarize_requests(exported["requests"]), indent=2)) Run it against your own downloaded file:
python summarize_requests.py internet-stability-test-results.json An empty input returns zero observations. A success separates two failure runs. A trailing failure run is retained. Invalid boolean or timestamp fields are rejected. The analyzer preserves the file's recorded order; use an unedited export from one session.
The first and last failed-sample timestamps are not the start and end of an outage. Sampling gaps, request timeouts and recovery between observations limit what can be inferred. One failed sample is still worth logging, but it does not establish that the whole connection was down.
Build an escalation note that another person can reproduce
Attach the original export and summarize:
- Date, time zone, actual session duration and the app symptom.
- Device, connection type, VPN state, test endpoint and approximate household load.
- Failed observations and their recorded clusters.
- The one-variable comparison that changed the result, including clean runs.
- What remains untested: another endpoint, another device, the local gateway or modem status.
Keep account details and private meeting links out of public reports. If you add a browser Network capture, review it before sharing: headers and URLs can contain sensitive information.
The goal is to turn “it keeps disconnecting” into a repeatable observation. That makes a router, application, VPN or provider conversation more precise without overstating what a browser can see.
For the broader home-network checklist, see the original short-drop troubleshooting guide.
Method references
- MDN: Using the Fetch API — request errors and HTTP response handling.
- MDN: Page Visibility API — background-tab behavior and visibility events.
- Microsoft: Fix Wi-Fi connection issues in Windows — platform troubleshooting context.

