A native macOS desktop app wrapping WhatsApp Web will be more reliable than headless browser automation
Native app achieved 99.2% uptime over 14 days vs 91.4% for headless. Eliminated 3 failure classes: GPU rendering crashes, headless detection, and prof
HypothesisA native macOS desktop app wrapping WhatsApp Web will be more reliable than headless browser automation
Native app achieved 99.2% uptime over 14 days vs 91.4% for headless. Eliminated 3 failure classes: GPU rendering crashes, headless detection, and profile corruption.

Changelog
| Date | Summary |
|---|---|
| 2026-04-12 | Initial creation |
Hypothesis
The auto-recovery and heartbeat experiments solved the problem of detecting and recovering from failures, but the headless browser runtime itself was the source of most failures. Puppeteer running WhatsApp Web in headless Chromium suffered from three recurring failure classes: GPU rendering crashes when processing media-heavy chats, WhatsApp’s headless browser detection triggering CAPTCHAs, and Chromium profile corruption after unclean shutdowns. The hypothesis was that wrapping WhatsApp Web in a native macOS Electron app (visible WebView, real GPU access, persistent profile) would eliminate these failure classes entirely and push uptime above 98%.
The tradeoff was clear: headless browser runs on any server, but a native app requires a Mac that stays on. For the single-operator use case (one WhatsApp account, one machine), the native app’s reliability advantages should outweigh the deployment flexibility of headless.
Method
The native app was built as an Electron application with a BrowserView pointed at web.whatsapp.com. Key architectural decisions: the WebView runs in a visible window (not hidden/offscreen) to avoid headless detection; GPU acceleration is enabled for media rendering; the Chromium profile persists to disk with write-ahead logging to prevent corruption; and the app registers as a macOS login item for automatic startup after reboot.
The comparison ran for 14 days in December 2025. Both systems ran simultaneously on the same Mac Mini, handling the same WhatsApp account (the native app was primary; the headless instance reconnected as a monitoring baseline whenever the native app was active). Uptime was measured as percentage of 5-minute intervals where the system could successfully send a self-message probe.
Failure events were categorized by root cause: GPU crash, headless detection, profile corruption, network transient, auth expiration, and other. Each system’s auto-recovery logic was identical (ported from the November experiment).
Results
Over the 14-day test period (4,032 five-minute intervals):
Native Electron app: 3,999 healthy intervals (99.2% uptime). 33 unhealthy intervals caused by: 2 network transients (8 intervals total, auto-recovered), 1 macOS sleep event that wasn’t properly intercepted (25 intervals until wake). Zero GPU crashes, zero headless detections, zero profile corruptions.
Headless Puppeteer baseline: 3,686 healthy intervals (91.4% uptime). 346 unhealthy intervals caused by: 4 GPU rendering crashes (112 intervals, required process restart), 3 headless detection CAPTCHAs (89 intervals, required manual solving), 2 profile corruptions (98 intervals, required profile rebuild), 5 network transients (47 intervals, auto-recovered).
The native app eliminated all three target failure classes (GPU crashes, headless detection, profile corruption) which accounted for 299 of the headless system’s 346 unhealthy intervals (86.4% of all downtime). The remaining failure: macOS sleep: was fixed post-experiment by adding an IOPMAssertion to prevent sleep while the app is running.
Findings
-
Visible WebView eliminates headless detection. WhatsApp’s bot detection checks for headless Chromium signatures (missing GPU info, specific user-agent patterns, absent WebGL extensions). A real Electron window with GPU acceleration passes all checks without any spoofing.
-
GPU access eliminates rendering crashes. Headless Chromium’s software renderer chokes on WhatsApp’s media previews (video thumbnails, high-res images, sticker animations). The native app uses the Mac’s GPU directly, which handles media rendering without issue.
-
Persistent profile with WAL prevents corruption. Headless Chromium’s default profile handling is not crash-safe. An unclean shutdown (OOM kill, power loss) corrupts the LevelDB stores. The native app’s write-ahead logging ensures the profile survives unclean shutdowns.
-
macOS power management is a real concern. The single failure in the native app was caused by macOS sleeping the machine during a period of low user activity. This is a solved problem (IOPMAssertion), but it would not occur in a headless server deployment. The tradeoff is real: native app requires a Mac that stays awake.
-
Same-phone mode is viable. Running the native app on the same Mac where the user works (rather than a dedicated server) is practical. The app consumes ~180MB RAM and negligible CPU when idle. The user can use WhatsApp normally on their phone; the desktop app handles automation in parallel.
Next Steps
With the native app shipping as the primary runtime, the next challenge was configuration management. The codebase had accumulated separate config files for message templates, routing rules, media handling, and schedule parameters. The skills config unification experiment consolidated these into a single declarative configuration. See experiments/openclaw/2025-12-22-skills-config-unification.