All reports
Technology by deep-research

Calendar Integration UX Patterns for Privacy-First Desktop Meeting Apps — Auto-Capture, Sync, and Notification Design

Remindr

Calendar Integration UX for Privacy-First Desktop Meeting Apps

Date: 2026-03-20 Context: Supports MOKA-272 (calendar integration frontend + meeting auto-capture magic moment) and MOKA-265 (Remindr MVP gates). Remindr is a Tauri 2 desktop app with local-first audio capture (Whisper + pyannote), processing everything on-device.


Executive Summary

  • The “magic moment” for meeting apps is zero-friction auto-capture — the app detects a meeting, starts recording, and delivers structured notes without the user doing anything
  • Two dominant architectures: bot-based (Otter, Fireflies, tl;dv) vs local capture (Granola, Krisp, Remindr). Bot-based has UX friction (visible to participants); local capture is invisible and privacy-preserving
  • Remindr’s competitive edge: 100% local processing (Whisper + pyannote + llama.cpp) vs Granola (local capture but cloud transcription). This is the strongest privacy story in the market
  • Calendar integration via OAuth2 PKCE (Google Calendar) + CalDAV (Apple Calendar) is the standard for desktop apps. Tauri has proven patterns via tauri-plugin-google-auth and local redirect server
  • The ideal UX flow: Calendar sync -> Meeting detection -> Notification toast -> One-click or auto-start -> Auto-stop -> Notes generation — all without leaving the desktop

1. Competitive Landscape: Calendar Integration Approaches

Bot-Based Tools (Join meeting as participant)

ToolCalendar MethodDetectionStart FlowPrivacy
Otter.aiOAuth (Google, Outlook)Auto-detect from calendarBot auto-joins via calendar linkBot visible to all participants
Fireflies.aiOAuth (Google, Outlook, iCloud)Calendar event scanBot joins automaticallyBot visible, can be blocked by host
tl;dvGoogle Meet/Zoom nativeCalendar integrationBot records via platformBot visible
FathomZoom/Google MeetPlugin + calendarAuto-record via pluginPlugin visible in toolbar

Local Capture Tools (No meeting bot)

ToolCalendar MethodDetectionStart FlowPrivacy
GranolaManual start (no calendar sync)None — user clicks “Start”Manual activation requiredInvisible to participants, but cloud transcription
KrispCalendar-aware notificationsCalendar scanNotification promptLocal noise processing, cloud for notes
MacWhisperCalendar event matchingMeeting detected notificationAuto-start with countdownLocal Whisper transcription
CirclebackCalendar sync (Google/Outlook)Auto-detect from calendarAuto-start with “Don’t Record” optionLocal capture, cloud processing
RemindrTo be built (MOKA-272)Calendar event + audio activityNotification + auto/manual100% local — strongest in market

Key Insight

Granola — the market leader in local capture — deliberately chose no calendar integration, relying on manual start. This is both a strength (simplicity) and a weakness (friction). Remindr can differentiate by combining Granola’s invisible capture with intelligent calendar-driven auto-detection.


The “Magic Moment” Flow

Calendar Event Approaching (T-2min)
         |
         v
  [Notification Toast]
  "Meeting: Weekly Standup (2:00 PM)"
  [Start Memory] [Skip] [Auto-start ON]
         |
         v (if auto-start or user clicks)
  [Recording Indicator]
  Minimal tray icon + subtle pulse
  Audio capture: mic + system audio
         |
         v (meeting ends or silence detected)
  [Auto-Stop + Processing]
  Whisper transcription (local)
  pyannote diarization (local)
  llama.cpp summarization (local)
         |
         v
  [Memory Created Notification]
  "Memory saved: Weekly Standup"
  [View] [Dismiss]

Three Operating Modes

ModeBehaviorTarget User
ManualClick “Start Memory” for each meetingPrivacy-conscious, selective recording
Notify + ConfirmNotification toast before each calendar meeting, one-click to startDefault — balances automation with control
Auto-CaptureAutomatically starts recording when calendar meeting + audio activity detectedPower users who want zero-friction

Default should be “Notify + Confirm” — gives users control while reducing friction. Auto-capture is opt-in due to Remindr’s privacy-first positioning.


3. Calendar Sync Implementation Patterns

Google Calendar (Primary)

Method: OAuth2 with PKCE via local redirect server

Tauri Implementation:

1. User clicks "Connect Google Calendar" in Settings
2. Tauri spawns tiny local HTTP server (e.g., port 48271)
3. Opens browser: accounts.google.com/o/oauth2/v2/auth
   - client_id: Remindr desktop app
   - redirect_uri: http://localhost:48271/callback
   - scope: calendar.readonly, calendar.events.readonly
   - code_challenge: PKCE S256
4. User grants permission in browser
5. Browser redirects to localhost, Tauri captures auth code
6. Exchange code for access + refresh tokens
7. Store tokens in local encrypted store (Tauri keyring)
8. Sync events via Google Calendar API (polling every 5min)

Existing Tauri ecosystem support:

  • tauri-plugin-google-auth (crates.io) — full OAuth2 PKCE for Tauri v2
  • webbrowser crate for cross-platform browser launch
  • tiny_http for local redirect server

Permissions needed: calendar.readonly and calendar.events.readonly — read-only, no write access. This aligns with privacy-first positioning.

Apple Calendar (Secondary)

Method: Local CalDAV/EventKit (no cloud auth needed for on-device calendars)

macOS Implementation:

1. Request calendar access via macOS EventKit (Rust FFI or Swift bridge)
2. User sees native macOS permission dialog
3. Read events from all local calendars (iCloud, Google via CalDAV, Exchange)
4. No tokens needed — OS-level permission

Advantage: On macOS, Apple Calendar already aggregates Google/Outlook/Exchange calendars. If user has Google Calendar synced to Apple Calendar, Remindr can access it via EventKit without separate Google OAuth.

Tauri 2 approach: Use Tauri’s Swift plugin bridge (tauri-plugin-swift) to call EventKit APIs from Rust.

Microsoft Outlook (Tertiary)

Method: Microsoft Graph API with OAuth2 PKCE (same pattern as Google)

Scope: Calendars.Read (read-only)

Priority Order

  1. Google Calendar via OAuth2 PKCE — largest user base, well-documented Tauri plugins
  2. Apple Calendar via EventKit — native macOS feel, zero-friction for Apple users
  3. Outlook via Microsoft Graph — enterprise users, post-MVP

4. Meeting Detection & Auto-Start Patterns

Detection Signals

SignalReliabilityImplementation
Calendar event time matchHighCompare current time with synced events (T-2min to T+5min window)
Calendar event has meeting linkHighRegex match for zoom.us, meet.google.com, teams.microsoft.com URLs
Audio activity detectedMediumMonitor system audio output for voice activity (VAD)
Meeting app process runningMediumCheck for Zoom, Meet, Teams processes (macOS: NSWorkspace, Windows: process list)
Microphone activeMediumMonitor microphone usage (Notion uses this pattern)

Recommended combination: Calendar event time + meeting link + audio activity = high-confidence meeting detection.

Notification Toast Design

Based on competitive analysis (MacWhisper, Circleback, Notion patterns):

Timing: Appears T-1min before calendar event start (or immediately when audio detected during event window)

Layout:

+------------------------------------------+
|  [Remindr icon]  Meeting Detected        |
|                                          |
|  Weekly Standup with @team               |
|  2:00 PM - 2:30 PM                      |
|                                          |
|  [Start Memory]  [Skip]   [Settings]    |
|                                          |
|  [ ] Always auto-capture this meeting    |
+------------------------------------------+

Behavior:

  • Auto-dismiss after 10 seconds (MacWhisper pattern) if no action → default to NOT recording (privacy-first)
  • “Always auto-capture” checkbox = per-event-series opt-in for recurring meetings
  • Toast position: top-right (macOS convention), above other notifications
  • Sound: None (meeting is about to start, don’t add noise)

Auto-Stop Signals

SignalTrigger
Calendar event end time reachedPrimary — stop at scheduled end + 5min grace
Extended silence detected (>60s)Secondary — meeting likely ended early
Meeting app process closedSecondary — user left the call
User manually stopsAlways available via tray icon or keyboard shortcut

Grace period: 5 minutes after scheduled end before auto-stop, with notification: “Meeting ran over. [Keep Recording] [Stop & Save]“


5. Post-Meeting “Memory Created” Experience

This is the second magic moment — the user sees their meeting captured and summarized without any effort.

Flow

Meeting ends (auto-stop or manual)
         |
         v
  [Processing indicator in tray]
  "Creating memory..." (Whisper -> pyannote -> llama.cpp)
  ~30-90 seconds for a 30-min meeting (local processing)
         |
         v
  [Notification Toast]
  "Memory saved: Weekly Standup"
  "5 action items detected"
  [View Memory] [Dismiss]
         |
         v (user clicks View)
  [Memory Detail View]
  - Meeting title (from calendar)
  - Participants (from calendar invite + diarization)
  - Full transcript with speaker labels
  - AI summary (key points, decisions, action items)
  - Timeline with highlights

Participant Matching

Calendar integration enables a powerful feature: matching diarized speakers to calendar attendees.

Calendar attendees: [Alice, Bob, Carol]
Diarization output: [Speaker 1, Speaker 2, Speaker 3]
→ User maps once: Speaker 1 = Alice, Speaker 2 = Bob, Speaker 3 = Carol
→ Remindr remembers voice profiles for future meetings

This is a significant UX advantage over Granola (which has no calendar data for participant context).


6. Privacy Considerations for Calendar Integration

Data Minimization

DataStore locally?Send to cloud?Retention
Calendar events (title, time, attendees)Yes (SQLite)NeverUntil user deletes
Meeting links/URLsYes (for detection)NeverEphemeral (deleted after meeting)
OAuth tokensYes (encrypted keyring)Only to Google/Microsoft for authUntil revoked
Audio recordingYes (during processing)NeverDeleted after transcription
Transcript + summaryYes (SQLite)Never (unless Cloud mode via Remindr Gateway)Until user deletes

User Controls

  • Granular calendar selection: Choose which calendars to monitor (e.g., “Work” but not “Personal”)
  • Per-meeting opt-out: “Skip” on notification toast
  • Block list: Never prompt for meetings with specific attendees or titles matching patterns
  • Meeting link filter: Only detect meetings on selected platforms (Zoom, Meet, Teams)
  • Auto-capture requires explicit opt-in per meeting series, never globally default-on

Privacy Messaging

For the Settings UI:

“Remindr reads your calendar locally to detect when meetings start. Calendar data never leaves your device. You choose which meetings to capture — Remindr never records without your knowledge.”


7. Technical Architecture for Tauri 2

Component Diagram

+-------------------+     +---------------------+
|   React Frontend  |     |   Tauri Rust Core    |
|                   |     |                      |
| Calendar Settings |<--->| calendar_sync.rs     |
| Meeting Notifier  |     |   - OAuth2 PKCE      |
| Memory Timeline   |     |   - Event polling     |
|                   |     |   - EventKit bridge   |
+-------------------+     |                      |
                          | meeting_detector.rs   |
                          |   - Event time match   |
                          |   - Audio VAD           |
                          |   - Process monitor     |
                          |                      |
                          | notification.rs       |
                          |   - Native toast       |
                          |   - Auto-dismiss timer  |
                          +---------------------+
                                   |
                          +---------------------+
                          |   SQLite (local)     |
                          | - calendar_events    |
                          | - memories           |
                          | - speaker_profiles   |
                          | - capture_preferences|
                          +---------------------+

SQLite Schema Additions

-- Calendar sources (Google, Apple, Outlook)
CREATE TABLE calendar_sources (
  id TEXT PRIMARY KEY,
  provider TEXT NOT NULL, -- 'google' | 'apple' | 'outlook'
  account_email TEXT,
  encrypted_tokens TEXT, -- encrypted access + refresh tokens
  calendars_selected TEXT, -- JSON array of calendar IDs to monitor
  last_synced_at TEXT,
  created_at TEXT DEFAULT (datetime('now'))
);

-- Synced calendar events (ephemeral, rolling 7-day window)
CREATE TABLE calendar_events (
  id TEXT PRIMARY KEY,
  source_id TEXT REFERENCES calendar_sources(id),
  external_id TEXT NOT NULL, -- Google/Apple event ID
  title TEXT,
  start_at TEXT NOT NULL,
  end_at TEXT NOT NULL,
  attendees TEXT, -- JSON array of {name, email}
  meeting_link TEXT, -- extracted Zoom/Meet/Teams URL
  auto_capture INTEGER DEFAULT 0, -- per-event-series preference
  UNIQUE(source_id, external_id)
);

-- Link memories to calendar events
ALTER TABLE memories ADD COLUMN calendar_event_id TEXT REFERENCES calendar_events(id);

Tauri Commands

// Calendar management
#[tauri::command]
async fn connect_google_calendar() -> Result<CalendarSource, Error>;

#[tauri::command]
async fn disconnect_calendar(source_id: String) -> Result<(), Error>;

#[tauri::command]
async fn get_upcoming_meetings(hours: u32) -> Result<Vec<CalendarEvent>, Error>;

#[tauri::command]
async fn set_auto_capture(event_series_id: String, enabled: bool) -> Result<(), Error>;

// Meeting detection (called by background service)
#[tauri::command]
async fn check_meeting_status() -> Result<MeetingStatus, Error>;
// Returns: NoMeeting | MeetingDetected(event) | MeetingActive(event)

8. Implementation Priority

Phase 1: Calendar Sync (Week 1-2)

  • Google Calendar OAuth2 PKCE connection
  • Event polling (5-min interval)
  • Settings UI: connect/disconnect, calendar selection
  • SQLite schema for calendar_sources + calendar_events

Phase 2: Meeting Detection + Notification (Week 2-3)

  • Background event time matching (T-2min detection window)
  • Native notification toast with Start/Skip/Settings
  • Meeting link extraction and platform detection
  • Auto-dismiss after 10 seconds

Phase 3: Auto-Capture + Auto-Stop (Week 3-4)

  • Audio activity detection (VAD) during meeting window
  • Per-meeting-series auto-capture preference
  • Auto-stop on calendar end time + 5min grace
  • Silence detection fallback (60s threshold)

Phase 4: Participant Matching (Post-MVP)

  • Calendar attendees → diarization speaker mapping
  • Voice profile learning (map once, remember)
  • Enriched memory view with named speakers

Phase 5: Apple Calendar + Outlook (Post-MVP)

  • macOS EventKit integration via Tauri Swift bridge
  • Microsoft Graph API OAuth2 PKCE
  • Unified calendar view across providers

9. Key UX Decisions for Product Team

DecisionRecommendationRationale
Default mode for new usersNotify + ConfirmPrivacy-first: never record without explicit action
Auto-dismiss notification behaviorDon’t record if dismissed/ignoredConsent-by-action, not consent-by-inaction
Calendar sync frequencyEvery 5 minutesBalance between freshness and battery/API limits
Detection windowT-2min to T+5minCovers early/late joiners without false positives
Auto-stop grace period5 minutes past scheduled endMeetings often run over
Meeting link requirementOptional (enhances confidence but not required)Some meetings are phone calls or in-person
Recording indicatorTray icon with subtle pulseAlways visible but non-intrusive (legal requirement in many jurisdictions)

Sources

Related Reports