What Breather can see, and what it can't.
How the Breather desktop app works, what it reads from a calendar, how call detection works without listening, and exactly what leaves the device. Written for the IT and security teams who approve it.
No servers, no accounts
Breather runs entirely on the Mac. There's no sign-in and no Breather server that receives calendar or user data.
Never records or listens
Call detection reads a single on/off signal from macOS: whether any microphone is in use. Breather doesn't even have microphone permission.
Read-only, minimal calendar access
Today's events only, a short list of fields, processed in memory. Descriptions, locations, attachments and attendee identities are never read.
Calendar content stays on the Mac
Meeting titles and details are never stored to disk and never sent anywhere: not to Breather, not to analytics, not in crash reports.
Optional, anonymous telemetry
Usage statistics and crash reports carry no names, emails or calendar data, and one setting switches both off.
Signed and notarized
Signed with an Apple Developer ID and notarized by Apple. Updates are signed the same way and checked by macOS before they install.
How it works
Breather is a menu bar app. It reads today's calendar, notices when calls start and end, keeps a running score of how demanding the day has been, and suggests a two-minute breathing exercise at a moment when there's room for one.
- Inputs: today's calendar (Google Calendar or the macOS Calendar app) and macOS's "microphone in use" signal.
- Processing: all on the Mac, in the Breather app. Nothing is sent to a server to be analysed.
- Outputs: a suggestion window on screen, and a local history of completed sessions for the user's own weekly stats.
There is no Breather account, login or backend database. Breather (the company) cannot see who uses the app, what's in their calendar or when they take a break.
Calendar access
The user chooses one calendar source during setup. Both are read-only, and Breather only ever looks at the current day.
Google Calendar
- Permission: Google OAuth with the read-only scope
calendar.events.readonly, plus the user's email address so Settings can show which account is connected. - Scope of reading: the user's primary calendar, today's events only, refreshed every 60 seconds.
- Tokens: the sign-in happens in the user's own browser and the token exchange goes directly between the Mac and Google. Tokens are stored on the Mac, encrypted with a key held in the macOS Keychain. Breather never receives them.
- Revoking: "Disconnect" in Settings deletes the tokens from the Mac. Access can also be revoked at any time from the Google account's security settings.
macOS Calendar app (including Outlook and Exchange)
- Permission: the standard macOS Calendars permission, which the user can revoke in System Settings at any time.
- Scope of reading: today's events from calendars added to the Calendar app on that Mac. Work Exchange or Microsoft 365 accounts added there are included.
- A small helper inside the app reads today's events through Apple's EventKit framework and passes on the same short list of fields as for Google. Event notes and links are scanned on the Mac only to find a video-call link; nothing else from them is kept.
Exactly what is read
| Read | Why |
|---|---|
| Start and end times | To know when meetings happen and where the gaps are. |
| Title | Kept in memory only, to recognise ad-hoc instant meetings. Never written to disk or sent anywhere. |
| Free / busy status | Events marked "free" are ignored. |
| The user's own response | Declined meetings are ignored. |
| Whether the user is the organiser | Organising a meeting counts as slightly more demanding. |
| Number of other attendees | Larger meetings count as more demanding, and one-person blocks (focus time, lunch) aren't treated as meetings. Only the count is used. |
| Whether it's a recurring meeting | Familiar recurring meetings count as slightly less demanding. |
| Video-call link | To offer a "Join meeting" button after a session if a call is about to start. |
Never read or requested: event descriptions or agendas, locations, attachments, attendee names or email addresses (for Google these fields are never requested; for macOS Calendar, attendee names are used only to count attendees and are never stored), other people's calendars, or any day other than today.
Microphone
Breather needs to know when a call ends, so it can suggest a break at that moment and never interrupt a meeting in progress. It does this without listening.
- Every few seconds, a small helper asks macOS one yes/no question: is any microphone on this Mac currently running? This is the same system state behind the orange microphone indicator in the menu bar.
- Breather never opens an audio input, never receives audio samples, and cannot tell which app is using the microphone, who is speaking, or what is said. Nothing about microphone state is stored or sent.
- Reading this signal doesn't need microphone permission, so Breather never asks for it. The app is also signed without the entitlement macOS requires before any app can capture from a microphone, so macOS would block it from recording even if its code tried. You can confirm this with
codesign -d --entitlements - /Applications/Breather.app. - Because it never captures audio, Breather never appears in the macOS microphone indicator, in Control Centre, or in the Microphone list in Privacy & Security settings.
What leaves the Mac
This is the complete list of outbound connections the app makes. Breather accepts no inbound connections.
| Destination | When | What's sent | Can be switched off |
|---|---|---|---|
Googleaccounts.google.comoauth2.googleapis.comwww.googleapis.com | Only if the user connects Google Calendar | The user's own OAuth token, to read their calendar as described above | Yes: use the macOS Calendar option, or disconnect |
Breather updatesupdates.breather.work(Cloudflare) | At launch and every 4 hours | A request for the latest version number; downloads of signed updates | No: needed to receive security fixes |
Usage statisticseu.i.posthog.com(PostHog, EU) | While the app is in use | A random install ID, app version, platform and chip type, and events such as "suggestion shown", "suggestion accepted", "session completed" and "setting changed", some with a numeric day-intensity score. No names, emails, calendar data or location. | Yes: Settings → Share usage data |
Crash reports*.ingest.de.sentry.io(Sentry, Germany) | Only when the app hits an error | The error's stack trace, app and macOS version. No console output, no user identifier, no calendar data. | Yes: the same "Share usage data" setting |
During Google sign-in only, the app briefly listens on a random local port on 127.0.0.1 to receive Google's redirect, then closes it.
Never sent anywhere: meeting titles or details, attendee information, audio or microphone activity, session history, or anything that identifies the user.
What's stored on the Mac
Everything lives in the user's own Library folder at ~/Library/Application Support/Breather/, readable only by that macOS user.
| Data | Contents | Kept for |
|---|---|---|
| Settings | Working hours, sound, suggestion frequency and similar preferences | Until changed |
| Session history | Time, length and breathing pattern of each completed session | 1 year |
| Suggestion history | When each suggestion appeared and the response, with the length and attendee count of the meeting before it (no titles or names) | 30 days |
| Today's state | The day-intensity score and calendar event IDs already counted, so a restart doesn't double count | Reset daily |
| Google tokens | Encrypted with a key held in the macOS Keychain | Until disconnected |
App security
- Code signing: signed with an Apple Developer ID, notarized by Apple, with the hardened runtime enabled. Verify any copy with
codesign -dv --verbose=2 /Applications/Breather.appandspctl -a -vv /Applications/Breather.app. - Updates: delivered over HTTPS. Before installing, the macOS updater checks that the update is signed by the same Apple developer team. Users choose when to install.
- Built on Electron: every screen is bundled inside the signed app; no web content is loaded from the internet. Screens run sandboxed, with context isolation and no direct access to the system.
- Footprint: no admin rights needed to run, no background services, kernel or system extensions, browser extensions or system-wide changes. An optional login item starts the app when the user logs in.
macOS permissions
| Permission | Used for | Required |
|---|---|---|
| Calendars | Reading today's events, only if the user picks the macOS Calendar option | No |
| Login item | Starting at login (a setting the user can switch off) | No |
Breather does not request Microphone, Camera, Screen Recording, Accessibility, Full Disk Access, Contacts or Location.
Deployment and removal
- Requirements: a Mac with Apple silicon (M1 or later) running macOS 12 Monterey or later.
- Install: a signed disk image containing
Breather.app, which can be deployed with standard Mac management tools. - Network allowlist:
updates.breather.work, pluseu.i.posthog.comand*.ingest.de.sentry.ioif usage data is left on, plus the three Google domains above if Google Calendar is used. - Removal: quit Breather, delete
Breather.appand the folder~/Library/Application Support/Breather/. Optionally remove the "Breather Safe Storage" item from the Keychain and revoke Google access from the Google account.
Questions
We're happy to go through any of this with your security team, or to answer a questionnaire. Email hello@breather.work, which is also the address for reporting a security issue.
This page covers the Breather desktop app. Team Breathers live sessions are covered in our privacy policy.