Privacy
Last updated July 31, 2026 · Applies to Etna 1.3 and later
Etna is private by architecture, not by promise. There is no Etna cloud, no account, and no server of ours anywhere. This page is the complete account of what Etna does with data — including, below, the entire vocabulary of the optional anonymous analytics: every signal the app can ever send.
The short version
- Your meetings never leave your Mac. Recording, transcription, and speaker separation run entirely on-device.
- Your notes are your files. Transcripts, summaries, and pre-meeting notes are plain markdown written straight into your Obsidian vault on your disk.
- Cloud summaries are optional and use your own API key. A transcript is sent to an AI provider only if you configured that provider yourself — directly from your Mac, never through us.
- Analytics are strictly opt-in. Off by default, anonymous, a closed list of counting signals — and you can turn them off at any time in Settings → General → Privacy.
What stays on your Mac
Live audio from your microphone and from other apps (Zoom, Meet, Teams…) is processed
on-device by Apple's speech models and on-device speaker separation. Transcripts,
summaries, pre-meeting notes, and the stakeholder pages in your People/
folder are markdown files in your vault — readable by anything, locked to nothing, and
never uploaded by Etna.
Voice profiles that let Etna recognize a named speaker across meetings are stored locally on your Mac.
Calendar data never leaves this Mac. Etna reads your calendar to detect meetings. Invite email addresses may be read transiently to infer a company label for a stakeholder page (e.g. "PandaDoc"); the addresses themselves are never written to your vault, never written to disk, and never sent anywhere. Even the opt-in analytics never use calendar data — participant counts, for example, come only from voices actually observed in the meeting.
Live translation runs on-device via Apple's Translation framework. Speech, speaker-separation, and translation models are downloaded once when needed; those download requests carry no user data.
Optional cloud summaries — your key, your choice
By default, meeting summaries run on Apple Intelligence, on-device and free. If you add your own API key for Claude (Anthropic), OpenAI, or Gemini (Google) and select it as your summarizer, the meeting transcript is sent to that provider to produce the summary. That request goes directly from your Mac to the provider under your key and their terms — Etna never sees, stores, or proxies it. No key configured, nothing is ever sent.
Anonymous usage analytics — opt-in, with the full vocabulary
Etna can send anonymous usage statistics through TelemetryDeck to help us understand which features matter and which errors happen in the wild. This is strictly opt-in:
- You are asked once — at the end of onboarding, or once in the app's panel for existing installs. Until you agree, the analytics library is not even initialized and zero network requests are made.
- Declining sends nothing — not even the decline itself. The opt-out rate is invisible to us by design.
- You can opt out at any time in Settings → General → Privacy → "Share anonymous usage statistics." Turning it off stops sending immediately and deletes the random install identifier; if you ever opt back in, you start as a brand-new anonymous install with no continuity to the old one.
- The identity attached to signals is a random per-install UUID, salted and hashed before transmission. No name, no email, no account — there is nothing to link it to.
What a signal can and cannot contain
- Closed vocabularies only: fixed category names, bucketed ranges, and true/false — never free-form text.
- Durations and counts are always buckets (e.g. "15–30 min"), never exact values.
- Never sent: audio, transcripts, summaries, meeting titles, filenames, vault or folder paths, people's names, calendar data, API keys, or error message text (error category names only).
Each signal is automatically accompanied by app version and build, OS version, device model and architecture, and locale — nothing else.
The complete signal table
This table is the entire vocabulary — the app cannot send a signal that is not listed here. It is published from the same file that gates our development process: a feature that adds a signal must update this table in the same change.
| Signal | Parameters | Fired when |
|---|---|---|
App.launched | autoRecord, autoDetectLanguage, summaryRouting (cloud/local), translationEnabled, detectionEnabled, peopleNotes, peopleFacts | The app starts |
Consent.granted | source (onboarding/settings/prompt) | You turn analytics on |
Onboarding.completed | — | Onboarding finishes |
Guide.completed | — | The first-run guide plays to its natural end |
Vault.configured | — | A vault folder is chosen successfully |
Meeting.started | origin (manual/autoDetection), sourceApp (meeting-app name from a fixed registry, or none), engine (sortformer/classic) | Recording begins |
Meeting.finished | durationBucket, participantBucket (observed speakers only), languages (e.g. en+ru), summaryEngine (appleIntelligence/anthropic/openai/google/none), summaryModel (catalog model ID / appleIntelligence / custom / none), summaryLatencyBucket (<5s … >3m), summaryOutcome (ok/failed/empty), transcriptionOutcome (ok/partial), translationUsed, origin, isFirst, speakersNamedBucket (0 … >5 — how many speakers ended with a real name; counts only, never the names), voiceAutoBucket, voiceSuggestBucket (0 … >5 — voice-memory auto-assignments / suggestion offers this meeting), acceptedDistanceBucket, rejectedDistanceBucket (<0.25 … >0.60 or none — median voice-match distances, per-meeting aggregates only, never per-speaker), voiceBar (0.40/0.45 — which voice-match threshold was active) | A meeting completes |
Meeting.discarded | durationBucket | You discard a recording |
Meeting.split | trigger (calendar/appChange), decision (auto/accepted/dismissed) | A back-to-back meeting boundary is handled |
Meeting.autoRecordCancelled | — | You cancel a pending auto-record |
Meeting.systemAudioStalled | reason (noAudio/noTranscription), elapsedBucket (<5m … >2h — how far into the meeting it happened) | The other side's audio goes quiet or stops transcribing mid-meeting (at most once per meeting) |
Meeting.tapRebuilds | countBucket (1-2/3-10/over10), trigger (deviceChange/rateDrift/starved/zeroByteStorm — the first rebuild trigger of the meeting) | A meeting finishes after its system-audio tap had to be rebuilt (e.g. you switched audio devices) |
Meeting.summaryRegenerated | summaryEngine/summaryModel (same vocabulary as Meeting.finished), summaryLatencyBucket, summaryOutcome (ok/failed), trigger (manual/sweep) | A summary that failed at meeting end is rebuilt from the saved transcript — via the finished card's "Try Again" or the automatic recovery on the next launch |
Error.occurred | code (error category name, other, emptyMeeting), context (start/recording/finalize/organizer) | An operation fails |
Organizer.suggestion | kind (folder/restructure), action (applied/snoozed/undone) | You act on an organizer suggestion |
Speakers.namesApplied | countBucket, surface (panel/review/popover) | You save speaker names (closing without changes sends nothing) |
Speakers.merged | — | You merge over-split speaker rows |
Notch.opened | — | The notch panel opens |
Scratchpad.opened | — | You open pre-meeting notes (closing sends nothing) |
Translation.enabled | — | Live translation is switched on |
Feedback.composed | diagnosticsIncluded | A feedback email draft is created |
WhatsNew.opened | source (autoOpen/settings) | The release-notes window opens |
PeopleNotes.written | createdBucket, updatedBucket (bucketed page counts — never who) | Stakeholder pages are updated after a meeting |
PeopleNotes.toggled | enabled | The stakeholder map is turned on or off |
PeopleFacts.extracted | factsBucket, peopleBucket (facts kept / pages that received them this meeting — bucketed counts only), droppedBucket (facts rejected by validation), engine (which summarizer ran, or none), outcome (ok/failed/timeout/skippedNoEngine) | Profile highlights are distilled after a meeting (never fired when there was nothing to extract for) |
PeopleFacts.toggled | enabled | Profile highlights are turned on or off |
PeopleFacts.consolidated | pagesBucket (pages that completed a pass), supersededBucket (facts a model correction archived), archivedBucket (facts the staleness and cap rules archived), outcome (ok/partial/failed) | The once-a-day background tidy of profile highlights does work |
Current as of Etna 1.4. Signal names are stable — a rename is treated as a breaking schema change.
Deliberately not tracked
Some things are untracked as a decision, not an omission:
- Declining or revoking analytics consent — the opt-out rate is invisible by design; that is the trade for trust.
- The languages suggested at first launch from your keyboard layouts — locale lists are an open vocabulary and never ride a signal.
- Scratchpad formatting actions, tab switches, Settings opens, notch closes, What's-New reading depth — noise over signal.
- Anything per-keystroke or per-render. Signals fire on committed actions and final outcomes only.
- The stakeholder map's content — names, meetings, inferred organization labels are vault markdown on your Mac, never telemetry.
- Profile highlights content. With this feature on, Etna writes automatic,
unreviewed, model-derived notes about the people you meet — their role, current work,
decisions, who they work with — into their pages in your own vault. Those statements
stay on your Mac: the bucketed counts in
PeopleFacts.extractedare the only thing this ever sends, never a name, a statement, or which category it fell in. It can be switched off under Settings → Automation → Profile highlights.
Software updates
Etna checks for updates once a day by fetching a static file (the Sparkle appcast) from this site. The request carries no account, no identifier, and no system profile — it is the same anonymous fetch your browser makes loading this page.
Feedback emails
"Send Feedback…" opens a draft in your email client — nothing is sent until you press send, and you see exactly what is in it. The optional diagnostics report is plain text you can read: app and OS versions, an allowlisted snapshot of settings, and the current run's app logs — with redaction enforced by automated tests. It never contains meeting content, names, file paths, or API keys.
Contact
Questions about any of this? Write to mail@j-alyavdin.com.