A native macOS menu bar app that monitors real internet connectivity and alerts you when the connection drops. Stays subtle when everything works.
macOS can show Wi‑Fi as connected while pages fail to load — router issues, ISP outages, captive portals, and DNS failures all leave the system indicator green. Online probes your network in layers and only surfaces alerts when something is actually wrong.
| macOS indicator | Online |
|---|---|
| Link up (Wi‑Fi/Ethernet) | Layered reachability probes |
| No failure attribution | Router, DNS, ISP, captive portal, custom host |
| Silent failures | Notification on confirmed outage + restore |
| No history | JSON outage log with timestamps |
Alert-first by design — the opposite of menu bar clutter. You forget it exists until your VPN dies mid-call and macOS never told you.
- Layered Sentinel probes —
NWPathMonitor, gateway TCP reachability viaNWConnection, DNS lookup, HTTP HEAD (captive.apple.com+cloudflare.com), optional custom hosts - Smart debouncing — 15s evaluation window, 15s wake-from-sleep grace, 2-tick recovery confirmation, 3-tick rapid outage detection
- Failure attribution — know whether it's your router, DNS, ISP, captive portal, or a custom endpoint
- Outage log viewer — sortable in-app table; copy JSON or open file in Finder
- Menu bar visibility — hide the icon in Settings; monitoring and alerts continue
- Battery-aware — longer poll intervals on battery power
- Launch at login — via
SMAppService - Native Swift/SwiftUI — macOS 14+, no Electron, no dependencies
Healthy — menu bar popover
Traffic-light states — green (online), yellow (degraded), red (offline), gray (recovering)
- Download Online.dmg from Releases
- Open the DMG and drag Online to Applications
- Launch Online and grant notification permission when prompted
Signed and notarized DMGs are published when repo signing secrets are configured. Otherwise releases are unsigned — right-click → Open on first launch (see Signing).
Requirements: macOS 14 Sonoma or later, Xcode 15+
git clone https://github.com/Jubblin/online.git
cd online
open Online.xcodeprojOr from the command line:
xcodebuild -project Online.xcodeproj -scheme Online -configuration Release build
# App: build/Build/Products/Release/Online.app
chmod +x scripts/build-dmg.sh
./scripts/build-dmg.sh Release
# DMG: build/Online.dmg- Online appears in the menu bar (subtle when healthy)
- Click the icon to see current status, last probe time, and the most recent outage
- Open Settings to configure:
- Show in menu bar — hide the icon while keeping probes running (re-open Settings from the app menu if hidden)
- Polling interval — 2s, 5s, 10s, or 30s (doubles on battery, capped at 8s)
- Custom hosts — hostnames probed via HTTPS HEAD (e.g. work VPN endpoint)
- Launch at login
- View outage log… from the menu or Settings for full history in a table
Notifications fire on confirmed outage and when connectivity restores.
ProbeEngine (2s tick, battery backoff)
├── PathProbe NWPathMonitor — interface up?
├── GatewayProbe SCDynamicStore resolver + TCP reachability (NWConnection)
├── DNSProbe Resolve cloudflare.com
├── HTTPProbe HEAD captive.apple.com + cloudflare.com
└── CustomHostProbe User-defined hosts
ConnectivityStateMachine
├── 15s evaluation window
├── 15s wake grace (suppress sleep/wake blips)
└── States: Healthy → Degraded → Outage → Recovering
Outputs
├── MenuBarExtra UI (alert-first)
├── UserNotifications
└── OutageLog (JSON on disk)
| State | Menu bar | Alerts |
|---|---|---|
| Healthy | Subtle green dot | None |
| Degraded | Warning icon | None |
| Outage | Wi‑Fi slash | Notification |
| Recovering | Spinner | None |
# Run the full local health stack (lint, shellcheck, build, test)
chmod +x scripts/health.sh
./scripts/health.sh
# Or run unit tests only
xcodebuild test \
-project Online.xcodeproj \
-scheme Online \
-configuration Debug \
-destination 'platform=macOS'
# Bump version locally (CI does this on PRs)
./scripts/bump-version.sh patchSee CONTRIBUTING.md for PR workflow, version labels, and code guidelines.
Online/
Probes/ PathProbe, GatewayProbe, DNSProbe, HTTPProbe, ProbeEngine
State/ ConnectivityStateMachine
Services/ AlertService, OutageLog, WakeObserver, LaunchAtLoginService
Models/ ProbeResult, ConnectivityState, AppSettings
Views/ MenuBarView, SettingsView
OnlineTests/ State machine, snapshot, HTTP mock tests
scripts/ build-dmg.sh, bump-version.sh, health.sh
| Workflow | Trigger | What it does |
|---|---|---|
| CI | Push to main, PRs |
Test + build Release artifact |
| Release dispatch | Manual | Finalize CHANGELOG + tag v* |
| Release | Tag v* |
Signed/notarized DMG → GitHub Release |
| Release Store | Tag v* or manual |
Upload to TestFlight |
| Version bump | PR to main |
Auto-bump semver + build number |
Cut a release: Actions → Release dispatch on main, or see docs/RELEASE.md.
PR version labels: version:patch (default), version:minor, version:major
Renovate keeps GitHub Actions up to date (renovate.json).
CI can produce Developer ID signed and notarized DMGs when signing secrets are configured. For local distribution:
./scripts/build-signed-dmg.sh Release # requires DEVELOPMENT_TEAM + cert in keychain
# or unsigned:
./scripts/build-dmg.sh ReleaseAll items from the initial roadmap are shipped. See TODOS.md for future ideas.
- Online Check by Sindre Sorhus — alert-first HEAD probes (inspiration)
- Pulse — Swift menu bar network monitor (MIT)
Contributions welcome. Please read CONTRIBUTING.md and CODE_OF_CONDUCT.md.
See CHANGELOG.md.

