Privacy: what leaves your Mac

A complete list of every outbound connection Pulsaria makes, when each one happens, and what it carries.

Pulsaria stores your KPIs as plain files on your Mac and has no backend for your data. That said, it is not an offline-only app: it fetches numbers from the services you connect, checks for updates, and talks to the licence server. This page lists every one of those connections, when it happens and what it carries.

Every outbound request, in one table

RequestGoes toHappens whenCarries
Connector fetchthe provider’s API, directly (Google, Plausible, Polar, Stripe, Awin)a connector KPI runs on its schedule, or you press Run now, Refresh or Testthe connection’s credential and its parameters
Google token exchangeoauth2.googleapis.combefore a Search Console or GA4 fetch, at most once per hour per connectiona JWT signed with your service-account key
Custom HTTP sourcethe URL you typedthat KPI runs or you press Run testyour URL and your header rows
Update checkwww.pulsaria-kpi.com5 seconds after launch, when the Updates card opens, and on Check nownothing but the request itself
Update downloadwww.pulsaria-kpi.comonly after you press Download & installnothing but the request itself
Licence activation / re-check / deactivationapi.polar.shon Activate, Re-check, Deactivate this device, and once on launch if the last check is over 30 days oldyour licence key and your Mac’s hostname
Crash reportingest.de.sentry.io (Sentry EU)only if you switched crash reporting on, and only on a crashexception type and stack trace

Everything else is local. Shell commands run on your machine, your data files are read and written on disk, and the trial is counted from two local files with no server involved.

With no connectors configured, no licence activated and crash reporting off — the state a fresh install is in — Pulsaria makes exactly one kind of outbound request: the update check.

Connector API calls

A connector KPI talks to the provider directly. There is no Pulsaria proxy, no relay, no middleman: the request goes from your Mac to searchconsole.googleapis.com, analyticsdata.googleapis.com, plausible.io, api.polar.sh, api.stripe.com or api.awin.com, and the answer comes straight back.

A fetch happens in exactly four situations:

  1. The KPI’s cron schedule is due and Pulsaria is running.
  2. You press the play button on a KPI card or Run now on the KPI detail page.
  3. You press Refresh in the Dashboard header, which runs every automatic KPI.
  4. You press Run test in the connection setup wizard, or the test button on a row in App Settings → Connections.

Each request carries the connection’s credential in an Authorization: Bearer header, the parameters you entered (site URL, property id, publisher id, region), an Accept: application/json header and the user agent pulsaria/<version>. Nothing about your KPI — not its name, not its target, not its history — is part of the request. Requests run in the app’s native layer with a 10-second timeout and a 64 KB cap on the response.

See Connectors for what each connector reads.

Google connectors and the token exchange

The two Google connectors need an access token before they can query anything. Pulsaria builds a JWT with the claims Google requires, signs it with the private key from your service-account file, and posts it to https://oauth2.googleapis.com/token. Google returns a short-lived access token.

Your private key itself is never sent anywhere — only the signature it produces. The returned token is cached in memory (not on disk) and reused until five minutes before it expires, so several KPIs on the same connection share one token for the hour. Quitting the app costs one extra token request on the next fetch.

Custom HTTP sources

A custom HTTP KPI sends a GET to the URL you typed, with the header rows you entered, and nothing else. Pulsaria does not inspect, log or forward that URL anywhere. The same 10-second timeout, 64 KB cap, http/https-only rule and five-redirect limit apply.

Header values on a custom HTTP source are stored in plain text in kpi-definitions.json — unlike connector credentials, they do not go into the Keychain, and they are included in a JSON export. If you paste an API token into a header row, treat your export file as a secret.

More in Custom HTTP sources.

Shell commands

A shell KPI runs /bin/sh -c <your command> on your Mac. Pulsaria sends nothing. If your command itself makes a network request — curl, or a CLI that calls an API — that request is yours, made under your account, and Pulsaria has no visibility into it beyond the number that lands on stdout. The command runs with a cleared environment (only PATH, HOME and LANG are passed through) and is killed after 10 seconds.

See Shell commands.

The update check

Pulsaria checks for a new version by requesting a manifest from https://www.pulsaria-kpi.com/api/update-check.php?c=pa_8x2rK9mVqL. That happens:

  • 5 seconds after the app window opens, silently — you only hear about it if there is an update,
  • once when the Updates card in App Settings comes into view, silently,
  • and each time you press Check now or Check again.

The request carries no account, no licence key and no device id. The ?c= token in the URL is the same string in every copy of Pulsaria; it only tells the server that the caller is the app rather than a crawler.

What the update server records

For requests that carry that token, Pulsaria’s server writes one row: a salted SHA-256 hash of the caller’s IP address, and a “last seen” timestamp. The raw IP is not stored, and the hash is not reversible without the salt. The row is overwritten on the next check, so what exists is a count of active installs, not a history.

This happens whether or not crash reporting is switched on — the two are unrelated. There is no preference to turn the startup check off.

Downloading an update

Nothing is downloaded or installed until you press Download & install. The package is then fetched from https://www.pulsaria-kpi.com/updates/Pulsaria.app.tar.gz and verified against a minisign public key compiled into the app; a package that fails that check is not installed. The app restarts itself when the install finishes.

Licence activation and re-checks

Licence handling goes to Polar, the payment provider, at https://api.polar.sh/v1/customer-portal/license-keys/. Three calls exist:

CallTriggered byBody
activateActivate in App Settings → Licenseyour licence key, Pulsaria’s public organization id, a device label
validateRe-check, and once on launch if the last successful check is over 30 days oldyour licence key, the organization id, the activation id
deactivateDeactivate this deviceyour licence key, the organization id, the activation id

The device label is your Mac’s hostname — $HOSTNAME, otherwise the output of hostname, otherwise the literal Unknown Device. It is sent so you can tell your devices apart in the Polar customer portal. Pulsaria never displays or edits it.

Two things worth knowing. First, the startup re-check only runs when a licence exists and its last successful verification is more than 30 days old — a licensed Mac does not phone home on every launch. Second, the trial involves no network at all: it is counted from ~/.pulsaria-trial and the first-launch timestamp in config.json, both local files. Buying happens in your browser on Polar’s checkout page; Pulsaria never sees a card number, and it never shows a price.

More in Trial & licence.

Crash reporting (opt-in)

App Settings → Crash Reporting → Send anonymous crash reports is off by default. While it is off, the Sentry SDK is not even loaded — it is imported only after you consent, so a non-consenting install never runs that code, let alone opens a connection.

With it on, two things are reported: a crash caught by the app’s error boundary, and an unhandled promise rejection. Reports go to Sentry’s EU region (ingest.de.sentry.io).

What a report contains

  • The exception type, its message and the stack trace.
  • The release tag pulsaria@<version> and standard SDK metadata.

What is removed before sending

  • Breadcrumbs — all of them. Console logs and DOM-interaction records are suppressed entirely, because scheduler logs contain KPI names.
  • The request, user and server_name fields, any extra payload and the trace context.
  • Absolute file paths in the message and in exception values, replaced with the literal <path>. An error thrown while writing to /Users/you/Library/… arrives as <path>.
  • Personally identifying data that the SDK would normally attach by default is switched off (sendDefaultPii: false).

Stack frames still name the app’s own bundle files and functions — that is what makes a report useful. They contain no KPI names and no values.

What is never reported

Errors the app handles itself are not sent: a failed fetch that you see as a toast, a rejected licence key, a connector test that fails. Crashes on the Rust side print to the system log and go nowhere. There is no product analytics, no usage tracking, no session replay and no feature flags anywhere in Pulsaria.

Switching the toggle back off closes the Sentry client immediately — no restart. There is no in-app view of what was sent and no delete-my-data button; that is a genuine gap, not a policy.

Things that only open your browser or mail app

Some buttons hand off to another application. Pulsaria transmits nothing itself:

  • Buy Pulsaria opens the Polar checkout page in your default browser.
  • The Setup Guide buttons in the setup wizard and the Official API docs link in the Connector Library open the relevant provider page in your browser.
  • Send feedback in App Settings → Feedback and Send request in the Connector Library both compose a mailto: draft to admin@one-pixel-ahead.com and open your mail app. Three lines are appended — Version:, Platform: and Locale: — under the heading “Sent automatically (no KPI data):”. You can edit or delete anything before you send, and nothing is sent unless you press send in your mail app.

What never leaves your Mac

  • Your KPI values and every entry you record.
  • Your KPI names, project names, targets, periods and connection names.
  • Alerts, the fetch log and your app settings in config.json.
  • Your data files themselves — export files are written only where you point the save dialog.
  • Connector credentials, in the sense that they go to exactly one place: the provider they belong to, as the Authorization header on that provider’s own request. They are never sent to Pulsaria, never written into a data file and never included in an export.

The app’s web layer is locked down to match: its content security policy permits connections only to itself and to Sentry. Every other request — connectors, HTTP sources, licence calls, the update check — is made by the native layer, which is why a connector KPI cannot be talked into calling anything the app did not build.

Where credentials are stored

Connection secrets go into the macOS Keychain, under the service name com.onepixelahead.pulsaria with an account name of connection.<connection-id>. You can see them in Keychain Access. The value is a small JSON object naming the credential type and holding the key or token.

What that means in practice:

  • The secret is protected by macOS, not by Pulsaria. It is covered by your Mac’s own encryption and login protection.
  • macOS may ask for permission the first time Pulsaria reads an entry. Choosing “Always Allow” makes later reads silent.
  • Deleting a connection removes its Keychain entry too.
  • A JSON export contains the connection’s name, connector and parameters plus the name of the Keychain entry — never the secret behind it. That is why moving to a new Mac asks you to paste each key again. See Backup, export & moving Macs.

Two files that are not in the Keychain and not encrypted:

  • license.json holds your full licence key in plain text, because re-validation needs it.
  • kpi-definitions.json holds the header values of custom HTTP sources in plain text, as noted above.

Everything else Pulsaria writes is plain, readable JSON. There is no encryption at rest and no password on the data files or on an export — the protection is your Mac’s, and where you choose to put the files. Where your data lives has the paths.

What Pulsaria does not have

No account, no sign-up, no email address required. No product analytics or usage tracking. No advertising or third-party trackers. No sync service run by us — syncing between Macs means pointing two installs at the same folder in your own cloud storage. No server-side copy of your numbers, because there is no server for them.

Didn't find it?

Write to us — a real person reads every mail, usually the one who wrote the feature.

admin@one-pixel-ahead.com