This page exists so you can see exactly what FerrLabs collects, in what shape, and how to turn it off. Nothing on this page is collected today. Telemetry is currently opt-in across every FerrLabs product. This document is the commitment we will deliver before flipping the default to on.
We will not switch to on-by-default until every event listed below is actually emitted, the opt-out mechanism works in all three surfaces (CLI, app, server), and this page is wired to read the event list from source code (so it cannot drift from reality). The work is tracked in FerrLabs-Cloud#166.
1. Why we collect anything at all
We ship five products. Without aggregate usage data we cannot tell which features are used, which paths break, which products to invest in. The honest options were either to operate in the dark or to collect the smallest possible signal — anonymous, hashed, with the full event list public. We picked the second.
2. What we never collect
Hard rules. Will never appear in any telemetry payload, regardless of opt-in / opt-out:
- Email addresses, names, avatars — any personally identifying string from your account.
- Secret values stored in FerrVault — the secret content, the metadata around it, the paths inside your vaults.
- Issue title or body in FerrTrack — only counts and event types, never content.
- Page content or analytics events from FerrGrowth visitors — your visitors do not become our data.
- Source code, commit messages, file paths handled by FerrFlow CLI.
- Prompts, completions, or any payload of FerrFleet agent runs — we record that a run happened and which first-party agent slug was used, never what it did.
- IP addresses — dropped at the ingestion edge before the event hits storage.
- Cookies or browser fingerprinting on ferrlabs.com or any product site.
3. What we do collect
Events are grouped by product. Every row is a real event name as it appears in the source code.
Once the work in #166 ships, this list will be generated from
Kit/crates/telemetry at build time — drift between docs and reality becomes impossible.
3.1 FerrFlow CLI
| Event | When it fires | Properties |
|---|---|---|
cli.run | Once per CLI invocation, after the command finishes. | command (enum: bump, release, changelog, …), exit_code (int), duration_ms (int), cli_version (string), os (linux/macos/windows), arch (x86_64/aarch64). |
cli.error | On unhandled error, instead of cli.run. | command, error_code (FFXXXX), cli_version. The
error message body is not sent. |
3.2 FerrLabs API + app.ferrlabs.com
| Event | When it fires | Properties |
|---|---|---|
org.created | New organization created. | org_hash, user_hash (the creator). |
org.member.added | A member is added to an org. | org_hash, actor_hash, role (owner/admin/member/billing/auditor). |
product.activated | An org activates a product subscription. | org_hash, product (enum), tier (free/pro/team/enterprise). |
product.tier_changed | Subscription upgraded or downgraded. | org_hash, product, tier_from, tier_to. |
product.canceled | Subscription canceled. | org_hash, product. |
auth.login | Successful login. | user_hash, method (password / oauth-google / oauth-github / sso). |
auth.signup | New account created. | user_hash, method. |
3.3 Per-product SaaS events
FerrVault, FerrTrack, FerrGrowth, FerrFleet emit usage counters that map to their catalogue
features (e.g. vault.secret.injected, track.issue.created,
growth.site.published, fleet.agent.run). Each product's full event
list lives under /telemetry# followed by its slug — populated when the product ships
and emits its first event.
4. Hashing
Every *_hash field is BLAKE3-keyed over the original UUID with a server-side
salt that rotates every 90 days. The salt is held in the FerrLabs Vault (sealed K8s secret today)
and is never written to client-readable storage.
Practical consequences:
- The same org or user produces a stable hash for ~90 days, then a new one. Cohorts can be analyzed inside a window; cross-window joins are impossible.
-
Even with the salt,
org_hashcannot be reversed to the original org id — BLAKE3 is a one-way function. - Without the salt, no rainbow table works against UUID space.
5. Storage and retention
- Where: a TimescaleDB hypertable in the FerrLabs primary Postgres cluster (EU, France). No third-party processor.
- Raw events: 90 days. Aligned with the salt rotation — old hashes and old data expire together.
- Aggregates: kept indefinitely as counts only (for example "
org.createdper day per product"). No per-event rows, no path back to a hash, no path back to an org. - Backups: same retention. Backup snapshots older than 90 days do not contain raw events.
6. How to opt out
Three surfaces, depending on the product:
6.1 FerrFlow CLI
Set either of:
FERRFLOW_TELEMETRY=0DO_NOT_TRACK=1(the cross-tool standard)
On first run after install, the CLI prints one line:
Telemetry on. See ferrlabs.com/telemetry. Opt out: FERRFLOW_TELEMETRY=0. Once opted
out, no event is generated. The CLI never silently re-enables telemetry between versions.
6.2 app.ferrlabs.com
A toggle lives at /settings/prefs → "Telemetry". Off applies to your account immediately; the next API call sets the server-side flag so even server-emitted events tied to your user_hash stop being recorded.
6.3 Org-wide opt-out
Org owners and admins can disable telemetry for the whole organization at /settings/org → "Telemetry". This overrides individual member preferences for events tied to the org (subscription changes, member additions, product usage). Personal events (login, signup) still respect the individual member's setting.
7. Verification
The events listed in section 3 are generated from Kit/crates/telemetry at build time
once #166 lands. You can audit the source at
github.com/FerrLabs/Kit/crates/telemetry.
If you want to inspect the wire format yourself, every event is a JSON POST to
https://api.ferrlabs.com/v1/telemetry. Run the FerrFlow CLI behind
mitmproxy or your DNS tooling of choice — the payload matches this page.
8. Changes to this document
Changes to the telemetry stance, the event list, the hashing function, or the retention policy
are documented in the public
changelog with the product: ferrlabs tag and the
type: security or type: breaking label as appropriate. We announce changes
that expand collection at least 30 days before they ship.
Questions: privacy@ferrlabs.com.