A macOS menu bar app that delivers unmissable Google Calendar meeting reminders. No more missing meetings because notifications blend into Slack noise.
Google Calendar's built-in notifications are easily missed:
- They look identical to hundreds of daily Slack messages
- They disappear silently if you're focused on work
- They don't scale urgency as meeting time approaches
- They fail silently when offline
GCal Notifier fixes all of this with aggressive, two-stage alerts that demand your attention when it matters.
Menu Bar: 📅 32m ← Live countdown to your next meeting
10 min before: 🔔 Gentle notification appears
"Team Standup in 10 minutes"
2 min before: ⚠️ Modal window + urgent sound
Can't miss it — requires action to dismiss
- Download from Releases
- Create OAuth credentials at Google Cloud Console (free)
- Launch the app — click 📅 in menu bar → Settings
- Paste credentials and sign in with Google
- Done! You'll never miss a meeting again
- Live Countdown — Shows time until your next meeting (e.g., "32m", "2h 15m")
- Today's Meetings — Click to see your full schedule at a glance
- Visual Indicators:
- 📹 Meeting has video link (click to see Join option)
- 📅 Meeting without video link
⚠️ Conflicting meetings at same time
- Quick Actions — Join, copy link, or open in Google Calendar
| Stage | Default | What Happens |
|---|---|---|
| Stage 1 | 10 min before | Notification banner + sound |
| Stage 2 | 2 min before | Modal window + urgent sound (can't ignore!) |
Both timing and sounds are fully customizable.
When the urgent alert fires, you get:
- Join — One click to open video call (Return key)
- Snooze — Push back 1, 3, or 5 minutes
- Open in Calendar — View full event details
- Dismiss — Close and acknowledge (Escape key)
- Snooze with Memory — Snoozed alerts show "Snoozed 2 time(s)" so you know
- Automatic Sync — Polls more frequently as meetings approach (1min/5min/15min)
- Offline Mode — Cached events keep alerts working without internet
- Sleep Recovery — Reschedules alerts after your Mac wakes up
Automatically extracts join URLs from:
- Google Meet
- Zoom
- Microsoft Teams
- Webex
- Slack Huddles
- Any URL in the event description
- Calendar Selection — Choose which calendars to monitor
- Keyword Blocking — Skip alerts for events containing "OOO", "Block", etc.
- Force-Alert Keywords — Always alert for "Interview", "Important", etc.
- All-Day Events — Automatically excluded (no alerts for holidays)
- Screen Share Detection — Suppresses modal popups during presentations
- Do Not Disturb — Optional sound suppression during Focus modes
- Back-to-Back Meetings — Intelligent alert handling for consecutive events
- Conflict Warnings — Alerts you about overlapping meetings
- ⌘⇧J — Join next meeting instantly (customizable)
- Return — Join from alert window
- Escape — Dismiss alert window
Download the latest .app from Releases and drag to Applications.
git clone https://github.com/ChrisEdwards/gcal-notifier.git
cd gcal-notifier
make startTo build without launching immediately:
make package RELEASE=1
open dist/GCalNotifier.appGCal Notifier needs OAuth credentials to access your calendar. This is free and gives you full control.
- Go to Google Cloud Console
- Create a new project (or use existing)
- Enable the Google Calendar API:
- Go to APIs & Services → Library
- Search "Google Calendar API"
- Click Enable
- Create OAuth credentials:
- Go to APIs & Services → Credentials
- Click Create Credentials → OAuth client ID
- If prompted, configure the OAuth consent screen first:
- User Type: External
- App name: "GCal Notifier"
- Add your email as a test user
- Application type: Desktop app
- Name: "GCal Notifier"
- Copy the Client ID and Client Secret
- Launch GCal Notifier — look for 📅 in your menu bar
- Click the icon → Settings
- In the Account tab:
- Paste your Client ID
- Paste your Client Secret
- Click Sign In
- Browser opens — sign in with Google and grant calendar access
- In the Calendars tab, select which calendars to monitor
Alerts Tab:
- Adjust Stage 1 and Stage 2 timing
- Choose different sounds for each stage
- Add a custom sound file if you want
Filters Tab:
- Add keywords to block (events won't trigger alerts)
- Add force-alert keywords (always trigger alerts)
General Tab:
- Enable "Launch at Login" for automatic startup
- Read-Only — Only requests
calendar.readonlypermission - Secure Storage — OAuth tokens stored in macOS Keychain
- No Tracking — Zero analytics or telemetry
- Your Credentials — You control the OAuth app; revoke anytime in Google settings
- Sandboxed — Minimal app permissions (network + keychain only)
- Check notification permissions: System Settings → Notifications → GCal Notifier
- Verify calendar is enabled: Settings → Calendars tab
- Check blocked keywords: Settings → Filters tab
- Force sync: Click menu bar icon → Refresh Now
- Check your internet connection
- Try signing out and back in (Settings → Account)
- Verify your OAuth credentials are correct
- No upcoming meetings with video links today
- Try clicking Refresh Now in the menu
- Check that you have calendars selected in Settings
GCal Notifier checks these locations:
- Google Meet conference data
- Event location field
- Event description (any URL)
Workaround: Add the meeting URL directly to the event description.
- Enable: Settings → General → Launch at Login
- Check: System Settings → General → Login Items
If building from source and getting repeated Keychain prompts:
./Scripts/setup_dev_certificate.shThis creates a self-signed certificate that persists across rebuilds.
- Xcode 16+ (Swift 6)
- macOS 15.0+
make build # Debug build
make start # Build, package, and launch dist/GCalNotifier.app
make stop # Kill running instance
make build-release # Optimized release build
make package # Create dist/GCalNotifier.app without launching itmake start, make package, and Scripts/compile_and_run.sh create a locally signed app that opens without an Apple provisioning
profile. The local signing path omits the restricted time-sensitive notification entitlement; signing that entitlement with the project's
self-signed development certificate causes macOS to reject the app at launch with security-policy error 163.
Everything else continues to work in a local build, including calendar sync, the in-app Stage 2 alert window, sounds, snooze and dismiss
actions, and durable Notification Center alerts. Stage 2 Notification Center alerts use the .active level locally, so Focus modes can
suppress them. Properly provisioned distribution builds keep the entitlement from GCalNotifier.entitlements and use .timeSensitive.
To inspect the entitlements applied to a packaged app:
codesign -d --entitlements :- dist/GCalNotifier.app 2>/dev/nullIf an older local package says it cannot be opened, rebuild it with make package or replace and launch it with make start.
make test # Run all tests
make check # Lint + static analysis
make check-test # Both checks and testsManual lifecycle and notification validation lives in
docs/testing/2026-04-28-alert-delivery-reliability-smoke-test.md.
make format # Auto-format code
make lint # Run SwiftLint
make all # Format, lint, testSources/
├── GCalNotifierCore/ # Testable business logic
│ ├── Auth/ # OAuth 2.0 + Keychain
│ ├── Calendar/ # API client, sync, filtering
│ ├── Alerts/ # Alert scheduling engine
│ ├── Settings/ # Preferences storage
│ └── Data/ # Caching and persistence
│
└── GCalNotifier/ # macOS app
├── MenuBar/ # Status item + dropdown menu
├── Alerts/ # Modal windows, sounds
├── Settings/ # Settings UI (SwiftUI)
└── Shortcuts/ # Global hotkeys
Two-Target Design:
- GCalNotifierCore — Business logic, fully testable without UI
- GCalNotifier — SwiftUI app with system integration
Key components:
SyncEngine— Adaptive polling (1/5/15 min based on next meeting)AlertEngine— Schedules and fires alerts with suppression logicEventCache— Offline-capable event storageKeychainManager— Secure credential storage
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Run
make allbefore committing - Submit a pull request
- Swift 6 strict concurrency
- Max 150 character lines
- Max 20 cyclomatic complexity
- Max 100 lines per function
MIT License
- KeyboardShortcuts by Sindre Sorhus
- MenuBarExtraAccess by Steffan Andrews