A macOS menu bar app that monitors websites for changes and sends native notifications.
demo.mp4
Notification badges get lost in browser tabs. Emails land in spam. Platform notifications assume you're checking constantly.
I missed a client message on Contra for two days because the badge was buried in 20 tabs. Built this to fix it.
WebWatcher reads from Safari tabs you already have open. No separate login. No browser extension. It uses AppleScript to run JavaScript in your existing authenticated sessions, then pipes results to macOS Notification Center.
- Menu bar app - Lives in your menu bar, not the dock
- Uses Safari sessions - No re-login required. Reads from tabs you're already logged into
- CSS selectors or XPath - Monitor any element: badges, message counts, text changes
- Smart filtering - Only notifies when values change. Badge went 2 → 3? Notification. Still 3? Silence
- Custom icons - Set a different icon for each watcher so you know which platform pinged you
- Configurable intervals - Check every 15 seconds to 30 minutes
- Native notifications - Shows up in Notification Center with sound
Everything stays on your machine. No servers, no analytics, no data collection. Configuration is stored locally at ~/Library/Application Support/WebWatcher/watchers.json. The app only talks to Safari via AppleScript. Nothing leaves your computer.
Configure URL, selector, watch type, and notification preferences.
Launch at login and other preferences.
| Type | What it does |
|---|---|
| Badge/Number | Extract a numeric value (unread count, notification badge) |
| Element Count | Count how many elements match the selector |
| Text Change | Notify when text content changes |
| Element Exists | Notify when an element appears |
| Element Disappears | Notify when an element is removed |
- Download the latest release
- Move
WebWatcher.appto Applications - Open the app (it appears in your menu bar)
- Grant permissions when prompted (see below)
- Open Safari and navigate to the page you want to monitor
- Add a watcher with the URL and CSS selector
WebWatcher needs three permissions to work. macOS will prompt for most of these on first run.
This is the most important one. Without it, WebWatcher can't read page content.
- Open Safari
- Go to Safari → Settings (or Preferences on older macOS)
- Click the Advanced tab
- Check Show features for web developers (this enables the Develop menu)
- Close Settings, then go to Develop menu in the menu bar
- Check Allow JavaScript from Apple Events
If you skip this step, watchers will fail with: "Enable 'Allow JavaScript from Apple Events' in Safari Settings → Developer"
macOS will show permission dialogs asking if WebWatcher can control Safari and System Events. Click OK on both.
If you accidentally clicked "Don't Allow":
- Open System Settings → Privacy & Security → Automation
- Find WebWatcher in the list
- Enable both Safari and System Events
macOS prompts for notification permission on first run. If you want to change settings later:
- Open System Settings → Notifications
- Find WebWatcher
- Enable notifications and choose your preferred alert style (Banners or Alerts)
- Open Safari → Develop → Show Web Inspector (enable Develop menu in Safari preferences if needed)
- Click the element inspector tool
- Click the element you want to monitor (badge, counter, etc.)
- Right-click the highlighted element → Copy → Copy Selector
Contra messages:
- URL:
https://contra.com/messages - Selector:
[data-sentry-component='Messages'] [class*='badge'] - Watch type: Badge/Number
Reddit notifications:
- URL:
https://www.reddit.com/ - Selector:
dynamic-badge[data-id="notification-count-element"] - Watch type: Badge/Number
- Badge Attribute:
initial-count - Note: Reddit uses web components with Shadow DOM, so the badge value is in an attribute
LinkedIn notifications:
- URL:
https://www.linkedin.com/feed/ - Selector:
.notification-badge__count - Watch type: Badge/Number
Rive Community:
- URL:
https://community.rive.app/ - Selector:
.notification-indicator, [class*='notification'] [class*='count'] - Watch type: Badge/Number
GitHub PR reviews:
- URL:
https://github.com/notifications - Selector:
.notification-indicator - Watch type: Element Exists
Safari suspends background tabs to save resources. If your watcher shows stale values, enable "Force refresh before checking" in the watcher settings. This reloads the tab before scraping.
The "Settle delay" option (0.5s - 5.0s) controls how long to wait after reload for dynamic JavaScript content to update.
- macOS 13.0+
- Safari with "Allow JavaScript from Apple Events" enabled (see Permissions above)
- Target page open in a Safari tab
- Automation permissions for Safari and System Events
- Notification permissions (optional, but recommended)
"Enable 'Allow JavaScript from Apple Events' in Safari Settings → Developer"
Safari's JavaScript access is disabled. See Permissions section above.
"Tab not found. Open [URL] in Safari."
The page isn't open in Safari, or the URL doesn't match. Make sure:
- The page is open in a Safari tab (not just bookmarked)
- The URL in your watcher matches what's in Safari's address bar
- You're not in Private Browsing mode
"Not permitted to send Apple events to Safari"
macOS blocked automation access. Go to System Settings → Privacy & Security → Automation → WebWatcher and enable Safari.
Watcher shows stale/unchanging values
Safari suspends background tabs. Enable "Force refresh before checking" in the watcher settings.
No notifications appearing
Check System Settings → Notifications → WebWatcher. Make sure notifications are enabled and set to Banners or Alerts (not "None").
cd WebWatcher
swift buildOr open WebWatcher.xcodeproj in Xcode and build.
MIT


