Personal productivity analytics for your Mac — counts keystrokes, clicks, scroll, and battery health entirely locally.
- Keystroke, left/right click, and scroll tracking
- Real-time WPM with 60 s sliding window and burst/repeat filtering
- Battery health, charge %, and cycle count via IOKit (sampled every 5 min)
- Activity sessions with idle detection (60 s threshold)
- Achievements unlocked by lifetime usage milestones
- All data stored locally in SQLite (
~/Library/Application Support/MacStats/macstats.db) - SvelteKit web dashboard embedded in the binary — no separate server needed
- CLI for quick stats without opening a browser
# 1. Build the dashboard
cd dashboard
npm install
npm run build
cd ..
# 2. Build the binary
cargo build --release
# 3. Install daemon + launchd agent (run once)
~/.local/bin/macstats install # or: ./target/release/macstats installinstall copies the binary into ~/.local/bin/MacStats.app, writes a launchd plist, and starts the daemon. Make sure ~/.local/bin is on your PATH.
MacStats needs two permissions under System Settings → Privacy & Security:
| Permission | Why |
|---|---|
| Accessibility | Required by the AX API to register a trusted process |
| Input Monitoring | rdev uses kCGEventTapOptionListenOnly; on Sonoma+ this requires a separate TCC grant. Without it the tap starts silently but no events arrive. |
macOS remembers permissions by bundle ID (com.graycup.macstats), so you only need to grant them once — even after rebuilding.
After granting both, run:
macstats daemon restart
macstats accessibility # confirms both are activemacstats # today's overview (default)
macstats today # same as above
macstats keyboard # lifetime + today keystroke counts
macstats typing # WPM stats
macstats mouse # click and scroll counts
macstats battery # battery health and charge
macstats uptime # reboots, sleeps, wakes
macstats sessions # recent activity sessions
macstats achievements # unlocked milestones
macstats export json # dump all data as JSON
macstats export csv # daily history as CSV
macstats daemon start | stop | restart | status
macstats accessibility # check/request permissionsopen http://localhost:8421
The dashboard is served by the daemon on port 8421. It is embedded directly in the binary so there is nothing extra to run.
cargo build --release
macstats installinstall replaces the binary inside the bundle and restarts the daemon.
The macstats binary doubles as CLI and daemon (macstats serve). The daemon runs the rdev event tap on the main thread (required for the macOS CFRunLoop) and spawns a tokio runtime on a background thread for the Axum API server, per-minute aggregation, battery sampling, and system event watching. Metrics are flushed to SQLite every minute and rolled up from minute → hourly → daily → monthly on a schedule. The SvelteKit frontend is compiled to static files and embedded at build time via include_dir!.