What we store

Every field on our server, in plain language.
No more, no less.

Pulli doesn't use usernames or passwords. Generate a key (like pulli-XXXX-XXXX-XXXX) and that key is your account. The license and activation fields below are tied to that key. Event and metrics rows are not. Skipping an email means we never learn your name. The key still singles the account out.

The data

License keypulli-XXXX-XXXX-XXXX
This is your account. We look up your license and activations with it. No email required.
Emailoptional
Only if you attach one. We use it for receipts and account recovery. Leave it blank and we never see it.
License typefree or pro
The app checks this to know which features to unlock. Your key stays the same if you upgrade.
Coarse countryderived from IP
We derive your country from your IP at key generation, then throw the IP away. Powers the install map on this page.
IP addressrate limiting only
Never written to our database. The rate-limit counter in Cloudflare's edge key-value store is keyed by an HMAC of your IP rather than the IP itself, and expires within the hour. We read the IP to derive the country above. We don't send it to our payment processor. Creem works out currency and tax from the billing details you enter at checkout.
Device idHMAC of your key + Mac
Derived on your Mac as HMAC-SHA256(license key, hardware UUID). The raw hardware ID never reaches us. The same Mac with a different key produces a different id, so there is no cross-license correlation, and without the key an outsider cannot recompute it.
Generic device labele.g. "MacBook Pro"
Helps you tell your devices apart. We store the model name, never your Mac's hostname.
App versione.g. 1.4.2
Tells us when to prompt you about an update.
OS platform, architecture, versione.g. macOS, arm64, 15.4
Diagnostics. If something breaks on a specific macOS build, this helps us find it.
Last usedtimestamp
When the app last completed a license validation. Feeds the "active this week" counter. An activation that has not checked in for 180 days is released so the one seat can move to another Mac.
Plan flagscatalog for the type
What your key unlocks: product id, one-device seat, feature flags, expiry, and a marker for whether Pro came from a subscription or a one-time purchase. No payment details.
Device request tokenrandom, per activation
A random token minted when a device activates. Your app signs later requests with it so we can tell a real device from a replayed one. It points at the activation, not at you.
Eventspage views, downloads, update checks · 24 months
Type, source, country, timestamp, and for app events the CPU architecture, release channel, and a small blob like the version you updated from. No event row carries your key. App events carry a device pseudonym instead: an HMAC of your machine ID under a random per-month key that lives only in edge storage and dies after the current month plus one. While that key is live we can count distinct devices for the month. Once it is gone, those rows cannot be joined back to a device. A nightly job deletes rows older than 24 months.
Daily resource summaryopt-in · Share anonymous usage data
One anonymous row per UTC day when the toggle is on: min / avg / p95 / max for memory (RSS), CPU, thread count, and active download count. No license ID, email, or device id. No URLs, filenames, or bytes transferred.
Feature preference snapshotopt-in · Share anonymous usage data
Settings flags only: appearance (theme, vibrancy, animation, color mode, list view, menubar icon/speed), scheduler (status, retry, completion hook, work hours, prevent sleep), system (launch at login), extension (whether browser integration and skip-fetch-box are enabled in Settings), fetch (parallel downloads, threads, auto-checksum, auto-rename), network (speed limit on/off, proxy on/off), and notifications (enabled). Preference flags only. No install UUID, first-install day, marketing version, live extension-connected flag, proxy host, credentials, paths, or download content.
Metrics flush timeopt-in · timestamp
When the app last uploaded that day's anonymous usage summary. Used for freshness only.
Diagnostics idopt-in · app / extension Axiom only
When either share toggle is on, the app mints a random id and tags core (and extension-relayed) Axiom lines with it so one opt-in session's errors can be read as a sequence. The id lives only on your Mac while those toggles are on. Turning both off deletes it; turning them back on mints a fresh one. It is not your license, not your install id, and not the keyed device id above. Website operator lines do not use this id. Lines expire after 30 days.
Website operator error linealways-on on failure · Axiom when configured
From the pulli.app API Worker: failed request terminals and free-form error lines only (route, status, outcome, timing, machine error kind). Successful requests stay out of Axiom. No license key, device id, diagnostics id, email, or download content. Same Axiom dataset as app logs, tagged source=website so we can tell them apart. Not controlled by Settings.

What we don't store

This list covers our server. The app on your Mac stores your download queue and settings locally, which never leaves your device unless you turn on the setting below.

  • Any lasting record of your IP address
  • Your license key on any analytics row
  • Your browsing history
  • URLs or filenames of anything you download
  • How much you download or transfer speeds
  • Proxy host, credentials, or custom user agents
  • Payment details (Creem handles billing as our merchant of record)

Optional: share usage and diagnostic logs

Settings includes two toggles, both off by default. With both off, the app and browser extension send nothing to Axiom and no daily usage row.

Share anonymous usage data posts the daily resource summary and feature-preference snapshot to our API on Cloudflare (the opt-in fields above), and ships warn/error logs from the app (and, if the extension is installed, sealed extension diagnostics relayed through the app) to Axiom.

Share diagnostic logs is the fuller Axiom firehose for the app and extension (debug and above; never the lowest TRACE noise). It still includes the usage path for the daily summary.

Metric rows store no license, name, email, or device id. App and extension Axiom lines hold messages, component names, and timing data, tagged with a random diagnostics id minted for that opt-in and deleted when you turn both toggles off. We strip URLs, file paths, emails, tokens, and credentials before anything leaves your Mac. None of this includes what you download or how much. The extension never holds an Axiom token. Turn both toggles off anytime; new uploads stop immediately. Existing metric rows expire after 24 months, and Axiom lines after 30 days. Website operator logs (above) are separate and not gated by these toggles. See our privacy policy for the legal details.

Install activity

Total installs
Active this week
Countries reached