Skip to content

Telemetry & Privacy

Sellf sends anonymous, opt-out usage telemetry so the project can see which features get used and on which runtimes. The model deliberately mirrors n8n’s diagnostics (N8N_DIAGNOSTICS_ENABLED): it is on by default, anonymous, and switched off entirely with a single environment variable. There is no in-app toggle and no first-run banner — disclosure lives here, in .env.example, and in a one-line notice printed to the server log on boot.

Telemetry only sends when all of these are true:

  • NODE_ENV=production
  • telemetry is not disabled by env (see Opting out)
  • the deployment host is public — it is skipped on localhost, *.local, dotless single-label hosts, and private IP ranges (10.*, 192.168.*, 172.16–31.*, 127.*)

It is driven by the Next.js instrumentation register() hook on boot plus an hourly in-process timer. A daily cadence gate in the database (an atomic claim-then-confirm on a singleton row) means a report leaves at most about once every 20 hours, no matter how often the process restarts. Sending never throws and never blocks the app — a failed send is simply retried on the next window.

  • Software & runtime versions — Sellf app version, runtime (node) and its major version only.
  • Coarse host buckets — CPU count band, RAM band (e.g. 4-8 GiB), OS platform, CPU arch. Exact values are bucketed before they ever leave the instance.
  • Feature flags — which integrations/config are enabled (Stripe mode, tax mode, embed/subscriptions/license-keys enabled, GTM, Meta Pixel, Umami, Facebook CAPI, Google Ads, currency API, captcha provider, OAuth provider count, etc.). Booleans and labels, never credentials.
  • Coarse capped counts — number of products, users with access, completed transactions, subscriptions, coupons, webhooks, API keys, and similar. Counts only, capped — never sums of money.
  • A random per-instance id — generated by the database (gen_random_uuid()), not derived from your domain, license, or any host fact.
  • License tierfree / registered / pro / business.
  • ❌ Emails or any customer / user rows
  • ❌ Revenue, order amounts, or any money figures
  • ❌ Your raw domain or hostname
  • ❌ Your license key (only the coarse tier)
  • ❌ IP addresses
  • ❌ Any other personally identifiable information

The outgoing payload is validated before every send, and the validation is tight where it matters most. The top level of the envelope and the identity block are strict: any undeclared field there (an email, a license key, a raw host fact) fails the check and the report is dropped rather than sent — it is impossible to silently ship a new top-level or identity field without declaring and reviewing it. The deployment and metrics sections are open maps by type but curated in practice: deployment carries a fixed set of coarsened keys plus a curated flags object, and metrics holds numeric counts only (numbers, never strings), so no free-form string can ride along inside them.

Reports are retained for 120 days, then deleted.

No. Because Sellf telemetry is anonymous and contains no personal data, it is not a processing of personal data on your behalf — no Data Processing Agreement is required for telemetry. (This is about telemetry only; your own handling of buyer data under Stripe/Supabase is separate.)

Opt-out is env-only. Set either of these in your .env.local and restart the app:

SELLF_TELEMETRY_DISABLED=true
# or, equivalently:
SELLF_TELEMETRY_ENABLED=false

Once disabled, the scheduler never arms and nothing is sent.

If you want the data but not on the default endpoint, point Sellf at your own receiver:

TELEMETRY_URL=https://your-receiver.example.com/v1/ingest

The URL must be https and must not resolve to a private / loopback host (an SSRF guard rejects those, and outbound requests use redirect: 'error'). The default endpoint is https://telemetry.techskills.academy/v1/ingest.