Skip to content

Opt-in usage analytics: onboarding prompt + PostHog client integration #2623

Closed as not planned

Description

@malibio

Summary

Add an opt-in usage analytics prompt to onboarding, and instrument nodespaced (the daemon, packages/daemon) with a PostHog client to send feature-usage and crash/error events when the user opts in.

Blocked by

Why

We want visibility into which features get used and where things crash/error, to prioritize fixes — without ever touching note content. Given NodeSpace's privacy-sensitive, open-source audience, this must be a genuine opt-in (default off), not an opt-out checkbox, and the copy must be specific and auditable rather than a blanket "no data collected" claim.

This must be instrumented at the daemon, not the frontend. nodespaced is a standalone OS-service process (launchd/systemd/autorun) that every client connects to over gRPC: the Tauri GUI (via packages/desktop-app/src-tauri's gRPC client), the standalone nodespace CLI (packages/cli), and external agents via the published skill (packages/skill). The Svelte frontend never talks gRPC directly — it goes through Tauri to the daemon. Instrumenting only the frontend would capture GUI usage alone and miss CLI- and agent-driven usage entirely, which is a real and possibly dominant usage path for this product. PostHog client init, event emission, and the opt-in check must all live in packages/daemon.

Confirmed during investigation: there is currently zero existing telemetry/analytics/crash-reporting code anywhere in the repo. The only superficially similar thing is packages/agent/src/local_agent/otlp_tracer.rs — dev-only OpenTelemetry tracing, off by default, explicitly localhost-only because traces contain full prompts/user content. Useful precedent for "we already treat this class of data as sensitive," not something to build on directly. There's also no existing panic hook in the daemon (main.rs only wraps a panicked gRPC task's JoinHandle in .context(...) and propagates it as an error) — crash reporting means adding a real panic hook, not wiring into something that exists.

Scope

Onboarding UI (Tauri frontend)

  • Add an analytics consent step to onboarding, default unchecked
  • Copy along these lines (finalize wording during implementation):

    Help improve NodeSpace
    Share anonymous usage analytics — which features you use, and crash/error reports — so we know what to fix and improve. We never collect your notes, titles, or file contents. Not used for ads or marketing, and you can turn this off anytime in Settings.

  • Equal-weight "Continue without sharing" path — skipping must not be harder or more buried than opting in
  • Persist the choice to a daemon-readable local file (e.g. under ~/.nodespace/), not just frontend local storage/settings — the daemon must be able to read consent state independent of whether the GUI has ever run
  • Expose a toggle in Settings to change the choice later; toggling must propagate to the daemon (e.g. daemon watches the file, or a gRPC call notifies it) so opt-out takes effect without requiring a daemon restart

CLI / headless first-run consent

  • If nodespaced is started and no consent file exists (e.g. a CLI-only user who never launched the GUI), the nodespace CLI needs its own first-run consent prompt — do not default to opted-in just because the GUI onboarding was never seen, and do not silently skip consent for this path

PostHog client integration (daemon, packages/daemon)

  • Add the PostHog Rust client to the daemon
  • Gate client initialization on the stored opt-in flag — do not initialize (even in a buffered/no-op state) until the user has explicitly opted in, to avoid any risk of pre-consent event capture
  • Disable autocapture and session recording in the client config (project-level default from Set up PostHog account and project for NodeSpace usage analytics #2622, but also enforce client-side)
  • Tag events with client type (GUI / CLI / agent-skill) where derivable from the gRPC call, so usage across all three surfaces is distinguishable, not just aggregated
  • Define initial event taxonomy — keep narrow for v1:
    • Feature usage: gRPC/tool calls invoked, by client type (exact list TBD during implementation)
    • Crashes/errors: daemon panics (via a new panic hook — none exists today), unhandled errors
    • Explicitly excluded: note content, titles, file paths, embeddings, any user-generated text or prompt content
  • Add a panic hook to the daemon that reports to PostHog (gated on opt-in) instead of only propagating as a JoinHandle error
  • Wire opt-out to fully stop event sending (not just pause) — flip back to opted-out should tear down the client
  • Read the API key via build-time config per the distribution decision made in Set up PostHog account and project for NodeSpace usage analytics #2622

Testing

  • Unit test: no events fire when opted out (client never initialized)
  • Unit test: opting out after opting in stops further events
  • Unit test: daemon started with no consent file and no GUI ever run does not silently opt in
  • Verify no note content, prompt content, or file paths ever appear in an event payload (spot-check taxonomy against this)

Out of scope

Activity

  1. malibio commented on Oct 3, 2026

    @malibio
    CollaboratorAuthor

    On hold: deferred until after the first release. The current direction is that the daemon and CLI never send telemetry; any analytics in the desktop app would be opt-in. Website and cloud-side analytics may be tracked later, outside core.

  2. malibio commented on Oct 11, 2026

    @malibio
    CollaboratorAuthor

    Closing as not planned in a backlog triage. On hold since early October, and the stated direction is that the daemon and CLI never send telemetry, which this set was written against. If opt-in analytics in the desktop app comes back, it is refiled in that form.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions