Go to file
sneak f4517ae953 Redesign summary box and add host pinning
Summary now shows current min/avg/max and history-window min/max.
Each host row has a pin icon that pins it to the top. Pinned hosts
sort alphabetically, unpinned sort by latency. datavi.be is pinned
by default.
2026-02-23 01:13:04 +07:00
src Redesign summary box and add host pinning 2026-02-23 01:13:04 +07:00
.dockerignore Bring repo up to REPO_POLICIES.md standards 2026-02-22 15:59:10 +01:00
.gitignore Initial implementation of NetWatch network latency monitor 2026-01-29 21:32:19 -08:00
.prettierignore Bring repo up to REPO_POLICIES.md standards 2026-02-22 15:59:10 +01:00
.prettierrc Enable prettier prose wrapping for markdown 2026-02-23 00:00:25 +07:00
Dockerfile Bring repo up to REPO_POLICIES.md standards 2026-02-22 15:59:10 +01:00
index.html Bring repo up to REPO_POLICIES.md standards 2026-02-22 15:59:10 +01:00
LICENSE Bring repo up to REPO_POLICIES.md standards 2026-02-22 15:59:10 +01:00
Makefile Add make dev target for running the dev server 2026-02-23 00:17:36 +07:00
package.json Bring repo up to REPO_POLICIES.md standards 2026-02-22 15:59:10 +01:00
README.md Add S3, GCS, and B2 regional storage endpoints 2026-02-23 00:35:07 +07:00
REPO_POLICIES.md Enable prettier prose wrapping for markdown 2026-02-23 00:00:25 +07:00
vite.config.js Bring repo up to REPO_POLICIES.md standards 2026-02-22 15:59:10 +01:00
yarn.lock Bring repo up to REPO_POLICIES.md standards 2026-02-22 15:59:10 +01:00

NetWatch is an MIT-licensed JavaScript single-page application by @sneak that provides real-time network latency monitoring to common internet hosts, displayed with color-coded figures and sparkline graphs, served from a static bucket or Docker container.

Getting Started

# Install dependencies
yarn install

# Development server
yarn dev

# Production build
yarn build

# Preview production build
yarn preview

# Docker
docker build -t netwatch .
docker run -p 8080:8080 netwatch

Rationale

When debugging network issues, it's useful to have a persistent at-a-glance view of latency and reachability to multiple well-known internet endpoints. NetWatch provides this as a zero-dependency SPA that can be deployed anywhere static files are served, with no backend required.

Design

The application is a single-page app built with Vite and Tailwind CSS v4. All code lives in src/main.js with a class-based architecture:

  • CONFIG: Frozen configuration object (update interval, timeouts, axis ticks, etc.)
  • HostState: Per-host state management — history buffer, latency tracking, status transitions
  • AppState: Top-level state container — WAN hosts, local hosts, pause state, aggregate stats
  • SparklineRenderer: Canvas 2D sparkline drawing with fixed axes, color-coded line segments, error regions, and DPR-aware scaling
  • UI functions: buildUI() constructs the DOM, updateHostRow() / updateSummary() / updateHealthBox() handle incremental updates
  • tick(): Main loop — measures all hosts in parallel via Promise.all, pushes samples, redraws UI. When paused, pushes blank markers (no probes, no false outage)

Monitoring targets

  • 22 WAN hosts: datavi.be, Anthropic API, OpenAI API, AWS Console, GCP Console, Azure, Cloudflare, Fastly, Akamai, GitHub, B2, 7 S3 regional endpoints (Cape Town, London, Bahrain, Tokyo, Sydney, Oregon, São Paulo), 4 GCS locational endpoints (Iowa, Belgium, Singapore, Sydney)
  • Local CPE: Cable modem at 192.168.100.1 (always monitored)
  • Local Gateway: Auto-detected on startup by probing common default gateway addresses (192.168.1.1, 192.168.0.1, 192.168.8.1, 10.0.0.1); first responder wins. Note: modern browsers enforce Private Network Access restrictions that block public-origin pages from reaching RFC1918 addresses, so local targets only work when NetWatch is served from localhost or a private address.

Local hosts are tracked separately from WAN stats.

Latency measurement

HEAD requests with mode: 'no-cors' and cache: 'no-store', timed with performance.now(). 1-second timeout; anything over 1000ms is clamped to unreachable. IPv4 only.

Color coding

Latency Color
< 50ms Green
< 100ms Lime
< 200ms Yellow
< 500ms Orange
>= 500ms Red
Unreachable Gray

Output structure

dist/
├── index.html
└── assets/
    ├── index-*.css
    └── index-*.js

Features

  • Real-time monitoring with 2s update interval and 300s history sparklines
  • Health indicator: green (HEALTHY) or red (DEGRADED) based on WAN reachability
  • Summary stats: reachable count, min/max/avg latency across WAN hosts only
  • Fixed chart axes: Y-axis 01000ms, X-axis 0300s
  • Color-coded latency figures and sparkline line segments
  • Play/pause: pause stops probes but history keeps scrolling (blank gaps, no false outage)
  • Clickable service URLs
  • Canvas-based sparkline rendering with devicePixelRatio scaling
  • Zero runtime dependencies: all resources bundled into build artifacts

Deployment

After running yarn build, deploy the contents of the dist/ directory to any static file host (S3, GCS, Cloudflare Pages, Vercel, Netlify, GitHub Pages) or use the Docker image behind a reverse proxy.

The Docker image:

  • Listens on port 8080 by default (override with PORT env var)
  • Trusts X-Forwarded-For from RFC1918 reverse proxies (10/8, 172.16/12, 192.168/16)
  • Sends access logs to stdout
  • Caches static assets with immutable headers

Browser Compatibility

Requires a modern browser with ES modules, Fetch API, Canvas API, and CSS custom properties.

Limitations

  • CORS: Some hosts may block cross-origin HEAD requests. The app uses no-cors mode which allows the request but provides opaque responses. Latency is still measurable based on request timing.
  • Local gateway: The 192.168.100.1 endpoint requires the host to be accessible from your network.
  • Network conditions: Measurements reflect browser-to-endpoint latency, which includes your local network, ISP, and internet routing.

TODO

  • Add unit tests
  • Add eslint for JS linting (currently lint target runs prettier only)
  • Add configurable host list (environment variable or config file)
  • Add latency history export (CSV/JSON)
  • Add notification/alert when status changes to DEGRADED

License

MIT. See LICENSE.

Author

@sneak