Privacy
Saykeep is a local-first application. Your audio, recordings, transcripts, and speaker labels are processed on your machine and stored only in your configured storage folder; summaries come from an OpenAI-compatible endpoint you configure — none is set by default, so summaries stay off until you choose one: a local server, or a service of your choice with your own API key. This is not a promise you have to trust — it is a property you can verify.
You decide where summaries go. Everything else stays.
Speech-to-text, transcripts and speaker labels always run on your computer — that part is not a setting. The only choice is who computes your meeting summaries. One setting. Three positions.
- Your audio
- Your transcripts
- Speaker labels
- Your files and your licence
Flip it all you like — the left column never changes.
Every connection the app can make — including the ones that have nothing to do with summaries — is listed below and, in full, in NETWORK.md. You can change this setting at any time.
Recording is always visible — there is no covert mode
Saykeep records out in the open. Whenever meeting capture is active, an always-on indicator shows it: the menu-bar icon, a status line with elapsed time and live audio meters, and the recording card. No setting or code path can suppress it. There is no hidden, discreet, or low-visibility recording mode in the product; this is a locked, test-enforced invariant, not a UI default that could be quietly changed. The first meeting you record also opens a consent notice, because in some places every participant must agree before you record (see the FAQ). Obtaining that consent is your responsibility; Saykeep’s job is to make recording impossible to miss.
You decide what’s kept
Saykeep doesn’t hoard recordings. Once a meeting is transcribed, it can delete the audio for you — asking after every meeting, or automatically cleaning up audio older than a number of days you choose. The guard rail: audio is deleted only when a successful transcript exists, and transcripts and summaries are never deleted automatically. You can also delete any meeting entirely from the recordings browser, or erase your Saykeep content — recordings, models, settings — in one guarded step (you type ERASE to confirm). It’s all plain files in your own folder; what stays is up to you.
The short version
127.0.0.1 and it stays on your machine). On first run, the speech models download once (full list below).The one exception during normal use — the update check
Saykeep can check whether a newer version exists. This check is off by default and never opens a connection unless you turn it on. When enabled, it makes at most one request per day to saykeep.app for a small signed file listing the current version. That request carries a standard User-Agent naming the app and its version (Saykeep/<version> Sparkle/2.9.6) and nothing else — no machine id, no account, no licence key, no cookie, no identifier that could single you out or link two requests together. If you choose to install an update, Saykeep downloads and installs it only on your consent — never silently, and never while a meeting is recording. Leave the check off and Saykeep makes no update calls at all.
How to verify
sudo ss -tunp | grep saykeep or lsof -i -a -p <pid>. With summaries pointed at a local endpoint and models already downloaded, you will see zero outbound connections during normal use.Block the app in your firewall
Little Snitch, LuLu, a corporate proxy — take your pick. Saykeep keeps working: transcription and speaker labels never needed the network.
Turn Wi-Fi off
Once the models are on disk, record an hour-long meeting with the network off. The transcript and the speaker labels come out the same — the simplest audit there is.
# NETWORK.md — every connection Whisperer can make Whisperer is a **local-first** application. Your audio, recordings, transcripts, and summaries are processed on your machine and stored only in your configured storage folder. This document is an exhaustive, behavior-verifiable inventory of **every** network connection the app is capable of making — nothing else happens. You do not have to take our word for it: run a network monitor (Little Snitch on macOS, `lsof -i` / `ss -tunp` on Linux, a firewall log on Windows) and confirm the app opens only the connections listed here. *This file is kept in sync with the code. If you find an outbound connection not listed here, that is a bug — please report it.* ## The complete list | # | Host | When | What is sent | Contains your data? | Avoidable? | |---|------|------|--------------|---------------------|------------| | 1 | **The LLM endpoint you configure** (`llm.endpoint_url`; **no default** — until you set one, summaries are off and nothing is sent) | When a meeting summary is generated, and a `/models` health probe when you test the connection | The meeting **transcript text** (for summarization) or a models list request (for the probe) | **Yes — transcript text.** It goes only to the endpoint *you* set. Out of the box no endpoint is set, so nothing is sent at all; point it at a server on your own machine and nothing leaves it. If you point it at a cloud API, your transcript goes there **by your choice** | Yes — disable summaries / leave the endpoint unset. Meetings still record and transcribe fully locally | | 2 | **huggingface.co** (and its model CDN) | First time a model is needed: the Whisper-family speech-to-text models, and — only if you opt in to the Parakeet engine in Settings — the Parakeet-TDT-0.6B-v3 weights from the Hub repos `mlx-community/parakeet-tdt-0.6b-v3` (macOS) or `istupakov/parakeet-tdt-0.6b-v3-onnx` plus the `istupakov/silero-vad-onnx` segmenter it needs for long audio (Linux/Windows), each pinned to a fixed revision. Diarization models come from here **only if you added a Hugging Face token** (optional fallback — the default path is row 5) | A standard model **download** request; for the diarization models, your Hugging Face **token** in an `Authorization` header (only if you provide one) | No — these are downloads *to* your machine. Your token authenticates the download; no audio/transcript is uploaded | Partly — once models are cached locally they are not re-downloaded. Diarization is optional | | 3 | **huggingface.co/api** (token check) | Only when you click "Test" on the optional Hugging Face token field in Settings ▸ Diarization | Your HF token in an `Authorization` header, to verify it can access the diarization model | No | Yes — it only runs when you test the token | | 4 | **saykeep.app** (the update appcast) | At most once/day, only if you enabled updates (you are asked once at first run) | A GET of a static XML file. The request carries a standard User-Agent naming the app and its version — `Saykeep/<version> Sparkle/2.9.6` — and nothing else: no machine id, no account, no licence key, no cookie, no identifier that could single you out or link two requests together. Downloads and installs the release only when you consent | Your Saykeep version, and that a copy of Saykeep is checking. Nothing else about you or your machine | Turn it off in Settings ▸ General ▸ Check for updates and no request is ever made | | 5 | **models.saykeep.app** (the speaker-label model mirror) | Once, only if speaker labels (diarization) are enabled and the model is not yet on disk — shown in the "Getting Saykeep ready" download window | An anonymous GET of a static ~30 MB tarball (`diarization-v1.tar.gz`) — no machine id, account, token, or any identifier (the request carries only a generic HTTP-client name). The file is checksum-verified before it is installed | Nothing about you or your machine is sent | Yes — turn speaker labels off (Settings ▸ Diarization) and no request is ever made; once installed it is never re-downloaded | *Row 2 note (2026-09-05): 0.4.0 also made one small metadata request to huggingface.co each time a cached Whisper model loaded (at launch, when the meeting model loaded, and on every switch between the two) — the loader was handed a Hub repo name instead of the on-disk path. Found and proved on the wire while fact-checking the website (`docs/ceo/evidence/2026-09-04-hf-launch-metadata-request.md`), disclosed here the same day, and **fixed in 0.4.1**: a cached model now loads from its local snapshot with no request (wire proof: three requests → zero across load → meeting → dictation). It carried no token and no identifier. If you are still on 0.4.0, update, or block huggingface.co — the model loads from disk either way.* *Row 4 note: this check is off by default and never opens a socket while off.* *Row 4 honesty note (corrected 2026-08-30): this row previously claimed the check sends "no version string". That was wrong — the update engine (Sparkle) sends its standard User-Agent, which names the app version, and nothing in the app overrides it. The row now states what actually goes over the wire. Verify it yourself with Little Snitch or `tcpdump` per the "watch it live" section below — that is the point of this document.* *Row 5 note: this is the token-free replacement for the Hugging Face diarization download (rows 2–3). Those two rows now apply only if you chose to add a token yourself.* That is the entire list. ## What Whisperer **never** does - **No telemetry, analytics, crash reporting, or usage tracking.** No analytics SDK is linked into the app — and you can hold us to it from the outside: the rows above are everything, and the wire is checkable. - **No accounts, no login, no cloud sync.** There is no Whisperer server. Nothing is uploaded. - **Your recordings, transcripts, and summaries are never sent anywhere** except the transcript text to the LLM endpoint *you* configured (row 1). They are stored only in your storage folder. - **No license phone-home.** License keys are verified **offline** against a compiled-in public key — no activation server, no network call, ever. - **The diagnostics export** (Settings → Advanced) writes a **local file** you choose whether to share; it makes no network call, and it redacts secrets. ## Local helpers are not network connections Whisperer runs some local subprocesses — `pw-record` (Linux system audio), the bundled `whisperer-syscapture` (macOS system audio), `osascript`/`caffeinate` (macOS), and your OS's file-reveal command. These are **on-device** and open no network sockets. ## How to verify 1. **Watch it live:** macOS → Little Snitch; Linux → `sudo ss -tunp | grep whisperer` or `lsof -i -a -p <pid>`; Windows → Resource Monitor / firewall log. With summaries pointed at a local endpoint and models already cached, the only connection you will see during normal use is the **update check** — at most one request a day to the Saykeep appcast, and only if you said yes to it at first run (row 4). You will see your Saykeep version in that request's User-Agent, and nothing else identifying. The one other connection you may see is a **single** download of the speaker-label model the first time you open Saykeep with speaker labels enabled (row 5); it never repeats once the model is on disk. Turn the update check off in Settings and — once that one-time model download has happened, or with speaker labels off — you will see **zero** outbound connections. 2. **Inspect your config:** Settings → Advanced → "Export diagnostics…" shows your resolved `llm.endpoint_url` (credentials redacted) so you can confirm where summaries would go. 3. **Hold us to the contract:** Whisperer is closed-source, so instead of "read the code," this file *is* the auditable surface — the only things that ever open a socket are the rows above. If you ever observe a connection that is not listed here, that is a bug; report it and we will treat it as one.
Verify it yourself — the walkthrough
macOS — Little Snitch
Install Little Snitch (or its free companion, Little Snitch Mini), open its network monitor, and use Saykeep normally — dictate, record a meeting, generate a summary against your local endpoint. What you will see, once the models are on disk: nothing. No account, no telemetry, no licence check — unless you turned the daily update check on, or pointed summaries at a remote endpoint. Every one of those is listed in the table above.
Linux — ss / lsof
# (no output — zero sockets)
$ lsof -i -a -p $(pgrep saykeep)
# (no output — zero sockets)
If you ever see a connection that isn’t on the published list, that’s a bug — tell us.
This website is a separate thing — and it does measure visits
Everything above is about the Saykeep app on your machine: no analytics, no telemetry, no crash reporting, and you can watch the wire to prove it. This page — saykeep.app — is an ordinary website, and websites count visitors. We would rather tell you plainly than have you find it in a network monitor.
_ga) and receives your visit — pages viewed, device type, approximate location from your IP — on our behalf. We switch off Google signals and ad personalisation, so it is measurement only, never advertising. Google is a US company, so data may be processed outside the EU under its standard contractual clauses.localStorage, key sk-consent) and is never sent to us. Change it whenever you like from the “Cookies & analytics” link in the footer: withdrawing stops the tag and expires the _ga cookies. An ad-blocker, or JavaScript off, keeps Google out too.The two never meet. No analytics of any kind runs inside the app, and nothing on this website can see what you record, dictate or transcribe. Checkout is the third-party exception: it runs on Lemon Squeezy’s systems under Lemon Squeezy’s privacy policy.