📡 Overview

ClumsyLinkWatch continuously monitors your internet connection and classifies where a failure happens — your adapter, your router, your ISP's last mile, DNS, or the wider internet. When something breaks, it tells you whose fault it was, and it can export the evidence as an HTML or PDF report.

The app runs quietly in the system tray. You don't need to keep the main window open for monitoring to continue — closing the window minimizes to tray rather than quitting.

Installation

Download the installer from the Downloads page and run it. No admin rights are required for a per-user install.

SmartScreen warning Windows may show a SmartScreen prompt because the installer isn't yet code-signed. Click "More info" → "Run anyway" to continue. This is normal for a new independent app.

First Run

On first launch, ClumsyLinkWatch immediately starts monitoring with sensible defaults:

  • Probing every 5 seconds while healthy
  • Default DEGRADED thresholds — loss above 1% is flagged, above 3% is treated as a serious problem
  • 90 days of raw samples retained, then rolled up to per-minute averages (configurable in Settings)

You can adjust probe targets, thresholds, and alert channels at any time in Settings.

🪜 The Probe Ladder

Pinging one address and calling a single failed reply an "outage" produces reports that ISPs dismiss — correctly. ClumsyLinkWatch instead checks five rungs, in order, cheapest and closest first, every cycle:

RungTargetIf it fails
0Local adapter stateCable unplugged / Wi-Fi dropped — your fault
1Default gateway (ICMP)LAN or router fault — your fault
2ISP first hop (from traceroute)Last-mile fault — the ISP's fault, highest evidentiary weight
3DNS resolution (multiple resolvers)DNS fault — a separate class ISPs often try to blame on the user
4Internet quorum — 3+ independent anchors (ICMP + HTTPS)Upstream/transit fault — the ISP's fault

Rung 4 requires a quorum — all anchors down — before declaring an internet outage. One anchor failing on its own is a note, not an event; ISPs and CDNs have their own outages independent of your link.

Why the ISP-hop rung matters Many routers respond to a TTL-expired traceroute probe but not to a direct ping. ClumsyLinkWatch probes the ISP hop at the depth discovered by traceroute rather than pinging it directly, which avoids false last-mile-down readings on routers configured that way.

🏷 Fault Classification

Every detected event carries a class, and the class determines whether it counts against your ISP:

ClassMeaningIn ISP report?
ADAPTER_DOWNNetwork adapter is downExcluded
GATEWAY_DOWNRouter/LAN unreachableExcluded
LAST_MILE_DOWNISP's first hop unreachableIncluded — highest weight
DNS_FAILUREDNS resolution failingIncluded — flagged separately
UPSTREAM_DOWNInternet quorum failedIncluded
DEGRADEDLink up, but loss/latency past thresholdIncluded
HOST_SLEEPMachine was asleep or hibernating, confirmed by a Windows power eventExcluded entirely
MONITORING_GAPNothing was measured — the app was closed, or the machine was offExcluded entirely

Excluded events aren't hidden — they appear in the timeline and in a report's appendix, so the report can't be accused of cherry-picking data. Hiding them would look worse than showing them.

Why a DEGRADED event fired

"DEGRADED" alone doesn't tell you much — ClumsyLinkWatch records exactly which rung tripped it, whether it was loss or latency, and the measured value against the threshold it crossed. A single cycle can have more than one at once (e.g. DNS loss and ISP-hop latency both over threshold together) — all of them are recorded, not just the first one found. This detail shows up in four places:

  • Live, on the status card, for as long as the link stays DEGRADED
  • Click any event for the full Event Detail view — every probe result, DNS resolver, and quorum anchor at that moment, plus a plain-English "why" and a "what to do" suggestion, with a Copy Summary button for pasting into a ticket
  • In generated reports, as a Detail column in the outage table
  • On the remote LAN status page, including its own event detail popup
  • In Discord/Slack webhook alerts, once the event resolves
Per-rung, not just quorum Since baselines are computed independently for the gateway, DNS, and quorum rungs, a DEGRADED reason might point at any of them — a gateway or DNS rung that's quietly gotten slower trips it against its own baseline even while the quorum rung looks perfectly healthy. The ISP-hop rung is the exception: it counts for reachability and loss, but its latency figure is never used, because that rung times an ICMP time-exceeded reply generated on a router's rate-limited control plane and the number describes the router's load rather than your connection.
A breach has to persist Latency is judged across a window — three of the last five samples over threshold — not on a single probe. At roughly 17,000 samples per rung per day, any healthy link crosses a sensible threshold several times a day through ordinary jitter. Loss has always been measured as a rate over a window.

😴 Sleep, Host Gaps & Coverage

A laptop that sleeps for nine hours must never show up as a nine-hour outage. ClumsyLinkWatch watches Windows power events (suspend, resume, lock) and also detects wall-clock gaps much larger than the sample interval. Where Windows confirmed a suspend, the span is marked HOST_SLEEP; where the only evidence is that the clock jumped — the app was closed, or the machine was off — it is marked MONITORING_GAP, because those are indistinguishable from the clock alone and a report should not claim your machine was asleep when it may not have been. Both render as hatched gaps in the timeline, and neither is counted as uptime or downtime.

This is why your uptime percentage is measured over observed time, not calendar time. If the app watched 27 of the last 30 days, the figure describes those 27 days, and the report states the coverage and lists every gap with its exact start, end and duration. Time nothing was watching is removed from both sides of the calculation rather than quietly counted as working time — a report that credits unmonitored hours as uptime is the easiest kind for an ISP to discredit.

The practical consequence: if you want a continuous record, turn on Settings → General → Startup → Start ClumsyLinkWatch when Windows starts. Otherwise every reboot you don't relaunch after leaves a visible hole in the evidence.

🗂 The Screens

The app is split into screens instead of one long scrolling page, switched with the tabs at the top of the window. The toolbar on the right (Report, Snapshot, Settings, Help, About) stays available on every screen.

ScreenWhat's on it
DashboardStatus card, findings, timeline, probe ladder, connections — the "read at a glance" view
DiagnosticsNetwork adapters, outage timing, host clock, gateway restarts, SLA panel, 14-day latency trend, full traceroute hop table
Speed TestManual speed test, day/hour pattern heatmap, sortable history, Clear All
EventsThe full event list, filterable by attribution, class and date range; click for full detail
StarlinkOnly appears once enabled in Settings — real dish telemetry, alignment gauges, obstruction map

📊 Live Dashboard

The Dashboard is built to be read from across the room, not studied. Top to bottom it gives you the state of the link right now, what it has done today, and where any fault sits.

  • The status band — link state on the left, 24-hour ISP uptime on the right at full size, and a live trace of the last five minutes of round-trip time underneath. The trace marks your link's own normal latency as a dashed line and scales to your connection, so it reads the same way on 8ms fibre as on a 600ms satellite link. A failed probe leaves a gap rather than a spike down to zero, and the whole trace turns red while a fault is standing.
  • The uptime figure shows a dash, not a number, until monitoring has covered a full 24 hours. No percentage is claimed for time the app was not running — a fresh install cannot report uptime it never observed.
  • Four findings — whether the link is currently fit for a call, how it behaves under load, whether your own DNS resolver is the slow part, and how many ISP-attributable outages there have been in 24 hours.
  • The timeline — see below.
  • The probe ladder — see below.
  • Connections at the foot — which ISP your traffic is actually leaving through, and any second connection it has seen.

Connections, primary and secondary. The app identifies the ISP carrying your traffic by name, ASN and public address, and updates when that changes. Where it has seen more than one, they are ranked by how much observed time each has carried traffic — so the one you use most reads as Primary, the other as Secondary, and whichever is live right now is badged Active now. While there is only one connection and nothing has failed over, the whole section collapses to a single line.

  • Connections are identified by the operator that owns the address, not by the address itself. A dynamic IP renewing on the same provider is the same connection, and is never reported as a failover
  • They are discovered, not configured. ClumsyLinkWatch cannot read your router's WAN ports. Where this machine itself holds more than one route to the internet — two network adapters, each with its own gateway — the standby one is probed directly and monitored alongside the active link, so a backup that has quietly died is visible before you need it. Where instead a single router handles the failover for you and this machine sees only one connection, a standby link stays invisible until a failover actually routes traffic over it, at which point it appears, and its appearance is itself the proof the failover happened
  • Per-connection time totals only count time the app was running. A week with LinkWatch closed is not credited to whichever ISP happened to be active when you shut it
  • Registries return the legal entity, which is often not what anyone calls the service — Starlink comes back as "Space Exploration Technologies Corporation". The recognisable name is shown, with the registered entity underneath rather than instead of it: that is the name a support representative will know on a ticket

Reading the probe ladder. The five rungs are stacked with your own machine at the bottom and the open internet at the top, and a probe climbs the spine on every cycle. Where the climb stops is the finding.

  • Each rung names what it actually represents — Gateway is your router, ISP Hop is your provider's first hop — so you do not need to remember the ladder to read it
  • A failing rung is marked, and everything above it reads not reached rather than failed: those rungs were never probed that cycle, and reporting them as down would invent faults that were never measured
  • A line underneath states the conclusion plainly. When your own equipment answered and the failure is further out, it says so — that the fault begins upstream of your property. When the failure is your own router or adapter, it says that instead, and the event stays out of your ISP-attributable downtime
  • The climbing probe stops animating whenever anything is wrong, including during a DEGRADED event where every rung still answers. A cheerful sweep through a real fault would misrepresent the state
Captive-portal & DNS-hijack detection A separate check against a known-good endpoint runs alongside the probe ladder. If your network is intercepting DNS or showing a captive-portal login page, a warning banner appears above the status card — the kind of interception that could otherwise make the internet quorum check read as healthy when the connection is actually unusable.

Reading the Timeline

The timeline strip is proportional to real elapsed time, not to the number of samples — a 2-minute outage and a 2-hour outage look different widths even if each only produced a handful of failed probes.

  • Hover any segment for its exact start time, end time, and duration
  • Switch between Live / 24h / 7d / 30d zoom levels
  • Color-coded by class; sleep gaps are hatched, never solid

📄 Generating Reports

Open Report from the toolbar to generate an HTML or PDF evidence report.

  1. Pick a period — 7d / 30d / 90d presets, or a custom range
  2. Enter your ISP name, account/circuit number, and location (all optional, but they make the report look like a real document instead of a printout)
  3. Optionally enter your monthly bill amount to add a prorated credit estimate (see below)
  4. Choose HTML or PDF and generate

The report includes:

  • DNS resolvers — your own resolver set against the public ones on typical response time and failure rate, with the number of queries behind each figure. No comparison is drawn below 200 queries
  • Outage timing — whether your outages cluster at a particular time of day or day of week. It states the counts, and it will tell you when it is deliberately withholding a weekly conclusion because the monitoring window is not yet long enough to support one
  • Connections & failover — how long each connection carried traffic, every switch between them, and how long you were actually offline across each one. A switch with no outage around it is reported as no gap observed rather than as an instant handover — switch times come from a public-address check that runs every few minutes and additionally the moment any fault clears, so a failover that caused an outage is timed to within seconds of recovery, but one that caused no outage may have happened up to a check interval before it was noticed
  • Dish alignment — when you have locked a Starlink alignment reference, whether the dish held its aim for the period and by how much it deviated. This is what answers "your dish must have shifted" with a measurement. If the dish did move, it says so and gives the date
  • Provenance — the tool version, the exact period, how many samples the report drew on, and whether this machine's clock was synchronised to an internet time source (with the measured offset). Every timestamp in the report depends on that clock, so it is shown rather than assumed. There is also an integrity checksum: regenerating the report from the same data and period produces the same value, so two copies can be confirmed to describe the same measurements. It is not a signature and does not establish who produced a file
  • A headline uptime percentage, shown as "nines" too (99.5%, 99.9%) — the language SLAs use
  • A plain-English methodology paragraph explaining the probe ladder
  • An outage table of ISP-attributable events with evidence summaries
  • A full timeline chart and a latency/loss chart with baseline overlay
  • An appendix of every excluded event and why, plus raw sample counts
  • A speed test summary (average download/upload/latency) and the same recurring-pattern detection from the Speed Test screen, when any tests exist in the period

SLA credit calculation

If you enter a monthly bill amount, the report adds a second headline figure: a prorated credit, computed as a straight line — ISP-attributable downtime as a fraction of the billing period, applied to the bill amount. No multipliers, no penalty math, just "you paid for a month, this much of it didn't work." It's not a legal claim or an ISP-issued credit — it's a defensible starting number for a support call, a billing dispute, or a small-claims filing.

Two different credit numbers, on purpose This report-time credit is separate from the live SLA panel in the main dashboard, which uses its own SLA target % and Credit $/day settings and only shows a credit once measured uptime actually drops below your configured SLA target. The report's credit is unconditional — it prorates every bit of ISP-attributable downtime in the period, breach or not.

🗒 Case Notes

Click any event to open its detail view, and you can attach your own notes to it: the support ticket number, who you spoke to, what they promised, and a date to follow up.

This is the half of a dispute the app cannot measure. On its own, a measured outage is a fact your ISP may not contest but will not act on; a broken promise on its own is your word against theirs. Together, in one document, they are much harder to wave away — which is why notes are carried into the report as a Case notes column beside the outage they belong to. The column only appears if you have written something.

Events with notes are marked in the event list, so a months-long argument stays visible without opening every row. Nothing you type here affects how an event is classified — your words are kept out of the measurement.

🔔 Alerts & Notifications

ClumsyLinkWatch sends a native desktop notification and flashes the taskbar icon when a real fault starts or ends — DEGRADED and HOST_SLEEP don't trigger the same urgency as a hard outage. You can also configure a Discord- or Slack-compatible webhook URL in Settings to get alerts wherever you already watch for things breaking.

🖧 Hardware Panel

On the Diagnostics screen, the Hardware panel lists your network adapters. For dual-WAN setups, ClumsyLinkWatch tracks your public IP and records a WAN-state change whenever it changes — a clean failover shows no connectivity gap; a rough one shows exactly how many seconds the failover took.

🔬 Diagnostics

Diagnostics carries the standing judgements — things the app has worked out about your connection over time, as opposed to the live readings on the Dashboard.

Outage timing

Looks for periodicity in ISP-attributable outages: a time-of-day cluster, or a day-of-week one. A concentration like that is the signature of scheduled maintenance, an automated restart or predictable congestion — not random faults — and it is among the most persuasive things you can put in front of a provider.

It is deliberately conservative and says so on screen. It draws no conclusion below 8 outages, a cluster has to clearly beat chance, and it will not assess day-of-week patterns until monitoring has covered at least three weeks — otherwise "it always happens on a Tuesday" cannot be told apart from "monitoring only ran on a Tuesday". When it is withholding a conclusion it tells you which one and why, rather than going quiet.

Gateway restarts

Appears only once you have told the app your gateway is ISP-supplied equipment (Settings → General). Providers reboot customer equipment on their own schedule, and that otherwise reads as purely your fault.

It flags gateway outages matching a restart signature: the outage lasted a plausible boot time, the device came back, and its address had to be re-learned on the local network afterwards. A rebooting device keeps its hardware address but drops off the segment; a device whose address genuinely changes was replaced rather than restarted, and that rules a restart out instead of supporting it. Duration alone is never enough — plenty of ordinary brief outages last about as long as a reboot.

It never reclassifies anything. The outage stays a local fault and stays out of your ISP-attributable downtime. What it adds is the reasoning, in the app and in the report's appendix.

Host clock

Every timestamp in every report comes from this machine's clock, so this is the reading that underwrites all the others. It shows whether the host is synchronised to an internet time source, which one, and the measured offset — and warns if the clock is unsynchronised or has drifted more than a couple of seconds. That is worth finding out before you build a case on those timestamps rather than after.

Also on this screen: your network adapters, the SLA panel, the 14-day latency trend, per-resolver DNS comparison, and the full traceroute hop table.

🚀 Speed Tests & History

The Speed Test screen has a manual "Run Speed Test" button, a day-of-week × hour-of-day pattern heatmap, and a full sortable history — every run, manual or scheduled, is saved.

Scheduling automatic runs

Turn it on in Settings under "Automatic speed tests" — Off, 30 min, 1h, 4h, 12h, or 24h. It's off by default. A real speed test moves real data (roughly 100–300MB per run), so Settings shows a live estimated MB/day next to whichever interval you're considering, and there's a toggle (on by default) to skip a scheduled run while a fault is already active — testing speed during a known outage just times out and adds noise, not evidence.

Why a speed test can't cause a false DEGRADED event A real speed test saturates your connection enough to cause a transient latency spike on the probe ladder's own pings (bufferbloat) — without accounting for that, a scheduled test could trigger a false DEGRADED reading against itself. ClumsyLinkWatch knows when a speed test (manual or scheduled) is running and suppresses DEGRADED classification for that window. Hard failures like LAST_MILE_DOWN still classify normally — only the loss/latency-threshold check is paused.

History and sorting

Click any column header to sort, or use the "Worst download/upload/latency first" buttons to jump straight to your worst readings. Rows note if the link wasn't healthy when a test ran (e.g. "during LAST_MILE_DOWN") — a bad reading during an actual outage isn't your ISP being slow, it's your ISP being down, and the history tells the two apart instead of mixing them together. Clear All wipes the saved history (with a confirmation) if you want a fresh start.

Pattern detection

The heatmap buckets every test by day-of-week and hour, and takes the median per cell — deliberately median, not average, so a single freak reading doesn't swing a whole cell. Once enough data exists, a callout appears automatically when a recurring window is meaningfully worse than the rest of your results (e.g. "Tuesdays around 20:00 are consistently 40% below your median download speed") — the kind of pattern that points at peak-hour congestion rather than a one-off. The same detection runs in generated evidence reports.

📶 Remote LAN Status

Turn on Enable Remote LAN Status in Settings to open a small read-only status page on your local network — useful for checking from your phone without remoting into the desktop ClumsyLinkWatch runs on.

  • The same big status card as the main app, plus the full probe ladder with live per-rung latency
  • Rolling loss percentage and a captive-portal warning banner when one is suspected
  • ISP/WAN info (public IP, ASN, location) and the 14-day latency trend chart
  • A full Speed Test section — latest result, day/hour pattern heatmap, and recent run history
  • The last 10 events, color-coded by severity — tap one for the same evidence popup the desktop app shows
  • Auto-refreshes every 5 seconds
No login, by design The page has no authentication — the trust boundary is "reachable on your own LAN," the same level as any other unauthenticated device on your home network. It's not exposed outside your network unless you specifically forward the port or put it behind something like Tailscale yourself.

Find it at http://<this-computer's-LAN-IP>:<port> from any device on the same network — the port is set in Settings (default 4173); the IP is whatever this computer's own local network address is (check Windows' network settings, or run ipconfig).

Settings

The gear icon opens Settings, organised as a sidebar of focused sections. Each section is sized to fit without scrolling at a normal window size:

SectionWhat's on it
GeneralISP name, account/circuit number, and location (pre-fills the report generator); SLA target % and Credit $/day; the Starlink toggle and dish IP address; the Privacy telemetry toggle
Your GatewayWhether the device you route through is ISP-supplied equipment (a combo modem/router) or your own router behind a separate modem. Asked once, and used only to decide whether an ISP-pushed firmware restart is even possible — see Troubleshooting. Leaving it unanswered keeps that detection off entirely
Alerts & RemoteWebhook URL for Discord/Slack-compatible alerts; Enable Remote LAN Status and its port
Speed TestAutomatic run interval (Off/30min/1h/4h/12h/24h), live MB/day estimate, and whether to skip while a fault is active
SensitivityDEGRADED latency multiplier, latency floor, and loss threshold — Strict/Default/Relaxed presets, custom values, and a Reset to Defaults button

DEGRADED thresholds are checked per-rung — a gateway or DNS rung that's quietly slowed down trips DEGRADED against its own baseline, not just the quorum rung. Latency must stay over the threshold across a window (three of the last five samples) before it opens an event, and the ISP-hop rung's latency is excluded from the check entirely.

🛠 Troubleshooting

The app shows "Starting up" and never finishes

This usually means a native module failed to load. Try reinstalling the latest version from the Downloads page; if it persists, send the error banner text to bugs@clumsyslab.tech.

My uptime percentage changed after updating

From 0.9.0 the figure is calculated over the time ClumsyLinkWatch was actually watching, rather than over the whole calendar period. Hours when the app was not running used to sit in the denominator and count as uptime, which flattered the number. If yours dropped, the new figure is the accurate one, and the report now shows exactly which spans were not monitored.

A report shows an outage during a time I know my PC was off or asleep

This should not happen — sleep gaps are excluded by design. If you see it, it's a bug; please report it with the exported report attached.

Updates aren't installing automatically

Open the About screen (ℹ in the toolbar) and click the refresh icon next to the version number to check on demand — it shows "Checking…", then "You're up to date" or "Update vX.X.X available" with a Download button, which becomes Restart Now once downloaded. If nothing shows up after a few seconds, download the latest installer directly from the Downloads page and run it over your existing install.

FAQ

Does this replace my router's built-in monitoring?

No — it complements it. ClumsyLinkWatch is specifically built to produce ISP-facing evidence, not to be a general network management console.

Will this make my connection look worse to my ISP by generating traffic?

No. The scheduler is rate-limited and staggered by design (5s when healthy, 2s during an active event for resolution, backing off to 30s after 10 minutes down) specifically so it never looks like a DoS source.

Is my monitoring data sent anywhere?

No — your probe results, events, and reports stay in a local database on your machine, full stop. See the Privacy Policy for details.

What about the anonymous telemetry?

Separately, as of v0.5.1, the app sends a small anonymous usage signal by default — app startup, app version/OS/architecture, that a report was generated (and its format), and that Starlink detection was turned on. It never includes probe results, events, IP addresses, ISP name, account number, location, or anything else you monitor or type into a report. Turn it off any time from Settings → General → Privacy; full details are in the Privacy Policy.

💬 Support

Email support@clumsyslab.tech for general questions, or bugs@clumsyslab.tech for bug reports. You can also join the Discord.