Skip to content
Halopen

privacy

The Halopen audit log: what it is and how to read it

Halopen records every cloud call from this Mac in a local audit log. Metadata only, never audio. Here is what each entry means and how to use it.

Halopen · · 5 min read

The Halopen audit log is a local, on-Mac record of every network call the app makes, surfaced inside Halopen Settings → Privacy → Open audit log. Each entry records timestamp, call type (Transcription, License check, Update check, Stripe checkout, Auth, Usage tick, Pre-flight gate, Billing portal), endpoint host, path, HTTP status, duration, and audio seconds. Metadata only — never audio, never transcripts. Capped at the most recent 500 entries on a ring buffer.

A dictation app makes network calls. To transcribe audio when the cloud mode is on. To check that your license is still valid. To count words against the monthly cap. To poll for updates. To open Stripe’s billing portal. To sign you in. These calls are not optional; they are the connective tissue between an app that lives on your Mac and a product that lives across machines.

The honest question is not whether the app phones home — it does — but whether you can see what it phones home about, when, and how often. For most apps, the answer is no. For Halopen, the answer is the audit log.

This post explains what the audit log is, how to find it, what each entry type means, and how to use it as a verification tool for the claims Halopen makes about privacy.

Where to find it

Open Halopen Settings. The hotkey is ⌘, when the app is focused, or pick Settings from the menu-bar icon at the top right of your screen.

Find the Privacy section in the sidebar. The first item is Audit log, with a button labeled Open audit log…. Clicking it opens a separate window listing every cloud call Halopen has made from this Mac, most recent first.

The window is a list, not a graph. Each row is one network call. The columns are short on purpose: time, type, host, path, status, duration, and where applicable audio seconds. There is no log search, no export, no upload-to-anywhere — the log is for your eyes, on your Mac, and that is all.

What each entry type means

Halopen recognizes eight distinct call types. Every entry in the log belongs to one of them.

Transcription. Your held-key audio sent to our transcription endpoint, transcribed by OpenAI’s gpt-4o-transcribe, returned as text, and discarded. The most frequent entry type in Cloud mode. The entry that should never appear during on-your-Mac dictation, because in that mode there is no transcription call to log.

Pre-flight gate. A small pre-flight check that fires before any large transcription, so Halopen can tell you immediately if you’ve hit the monthly free-tier cap or if your license has lapsed. This is faster than letting the audio upload only to be rejected at the end. Pre-flight entries have a tiny audio duration (or none) and complete in well under a second.

License check. Periodic re-verification of your subscription status against our backend. Fires when the app launches, when you wake your Mac, and at coarse intervals during long-running sessions. The call sends your license token and receives back the current subscription state.

Usage tick. Anonymous count of how many words you’ve dictated this month, flushed to the server so the menu bar and account page show accurate numbers. Counts words, not content — Halopen does not send what you said, just how many you said.

Stripe checkout. Opens when you click Upgrade to Pro, Manage Subscription, or any payment-flow CTA. The call gets a fresh checkout-session URL from our backend; Halopen then opens that URL in your default browser. The actual checkout happens at Stripe.

Billing portal. Opens when you click Manage Subscription in the account area. Same pattern as checkout — the call gets a portal URL, Halopen opens the URL.

Auth. Sign-in and sign-out flows. Magic-link requests, OAuth round-trips, token refreshes. Sees your email address (you put it in the sign-in field) and your account state; does not see passwords, because Halopen does not have any.

Update check. Halopen polling our app-cast feed for new versions, on a calm schedule of once or twice a day at most. The poll is a simple GET request to an XML file; it sends no personal information. Sparkle, the open-source update framework Halopen uses, surfaces this call through Halopen’s audit-log delegate so the privacy claim “every cloud call appears in a local audit log” stays true for update checks as well.

That is the complete list. There are no hidden call types, no telemetry pings, no analytics beacons. If you see a row in the audit log that doesn’t fit one of these eight, that’s a bug — please tell us.

What each entry records

Every entry, regardless of type, contains exactly the same fields:

  • Timestamp. When the call happened, to the second.
  • Type. One of the eight call types above.
  • Endpoint host. The hostname Halopen called. Almost always eayniihlsdntrendzeev.supabase.co for backend calls, or our Sparkle update host for update checks.
  • Endpoint path. The path within the host — e.g., /functions/v1/transcribe-audio-vf for a Cloud transcription, /functions/v1/license-check for a license verification.
  • Status code. The HTTP response code, or -1 if a network error happened before any response came back.
  • Duration. Round-trip wall time in milliseconds. A useful column when troubleshooting “is the transcription slow because of my network?” — you can see it.
  • Audio seconds. Present for Transcription and Pre-flight gate entries only. The duration of the audio sent. Useful for confirming your monthly minutes math.
  • Outcome. A short flag — ok, denied, error — and where applicable a brief detail.

That is the entire schema. No request bodies. No response bodies. No headers. No transcript content. No audio. The entries are designed to give you confidence in what Halopen is doing without exposing anything Halopen would not want to expose about you.

How the audit log is stored

The log lives in UserDefaults under the key halopen.auditLog.entries. It is JSON-encoded and persists across launches. It is capped at the most recent 500 entries on a ring buffer, which is enough for roughly a month of active dictation at fifteen to twenty calls per day. Older entries roll off naturally as new ones land.

It never leaves your Mac. Halopen does not synchronize it across devices. Halopen does not upload it for support purposes. Halopen does not include it in crash reports. If you switch Macs and want to bring it with you, you’d have to copy the UserDefaults plist by hand; we have not built that feature because it would be a privacy regression to ship a tool that moves the audit log over the wire.

If the log file is corrupted for any reason — disk error, manual edit, file-system anomaly — Halopen wipes it and starts a fresh log rather than crash. The log is a privacy/UX feature, not load-bearing infrastructure; its integrity is best-effort and its absence is non-fatal.

Why we built it

The audit log exists to make Halopen’s privacy claims falsifiable.

A privacy claim that you have to take on trust is worth less than a privacy claim you can verify from your own machine. Many dictation tools assert that they don’t keep your audio. Some of them mean it. Most of them are not in a position where you could independently confirm it from outside their network — the relevant call leaves your device, and what happens on the other side is opaque to you.

Halopen’s most load-bearing privacy claim is the on-your-Mac transcription invariant: in that mode, Halopen makes zero network calls during transcription. The audio is mel-spectrogrammed, encoded, decoded, and rendered to your cursor without ever going over the wire. We could just say so on the marketing page and ask you to trust us. We chose instead to ship the log so you don’t have to.

The verification is a minute of work. Set the mode to On your Mac. Dictate a sentence. Open the audit log. There should be no Transcription entry corresponding to your dictation. Other entries from other times — a License check from an hour ago, an Update check from this morning — may be present, and that is expected; none of them involve audio. The specific test is the absence of a Transcription row for your specific dictation. The promise is mechanical, not moral. The log proves it.

The same property holds for every other thing Halopen could in principle phone home about. Want to know how often the app checks your license? Filter the log to License check. Want to know whether the update poller is firing as advertised? Filter to Update check. Want to count your monthly minutes by hand? Sum the audio-seconds column on Transcription rows. The log is built around the idea that the user is the auditor of their own machine.

What changes if a future Halopen ships a regression

Halopen treats the audit-log invariant as a P0 brand-load-bearing claim. If a future build accidentally adds a network call to the on-your-Mac transcription path — through a misplaced refactor, an over-eager telemetry feature, a vendor SDK that phones home unannounced — the audit log will surface the new entry the first time it fires. The user will see it. The brand promise breaks immediately and visibly, not silently.

This is exactly the kind of failure mode we want. A privacy regression that is invisible is the worst kind; a privacy regression that the user can detect from their own machine within seconds of dictating is the kind we can ship a fast fix for. The audit log is the trip-wire.

If you ever see a Transcription entry in your audit log while you were dictating in On your Mac mode, that is a P0 bug and we want to know. Email [email protected] with the entry timestamp and we will investigate the same day.

The longer story

For the policy that governs what Halopen discloses publicly and what we hold close, see /transparency/. For the decision guide on when to use Cloud and when to use on-your-Mac, see /learn/cloud-vs-privacy-mode/. For the long-form explanation of why we built the on-device path in the first place, see /learn/why-halopen-runs-on-your-mac/.

The audit log is small, and the surface area it covers is narrow. It is also the single most important feature we ship for the customer who wants to use a dictation app without taking the privacy claims on faith. That customer was us. That customer is now you, if you want it to be.

Try Halopen

Hold the function key. Speak.

Halopen Free is 8,000 words a month, forever. Pro is $19/mo or $179/yr — unlimited.

Power-user cheat sheet

Take Halopen with you.

One short email, then the Halopen power-user cheat sheet — hotkeys, best-fit apps, custom vocabulary tips, voice patterns for prompt engineering. No spam. Unsubscribe in one click.