Skip to content

Telemetry ​

Motestack ships with a telemetry contract, not a telemetry pipeline. The goal is to have the call sites, types, and consent flow already wired so adopting a backend later (Plausible, PostHog, custom) is a single-file swap. No data is collected today.


Where it lives ​

src/features/telemetry/

types.ts        — TelemetryEvent union, TelemetryTraits
provider.ts     — TelemetryProvider interface + NullTelemetryProvider
index.ts        — public API: initTelemetry, setOptIn, track, identify, flush

Default state ​

  • The default provider is NullTelemetryProvider. Its init / identify / track / flush / shutdown are all no-ops.
  • The opt-in toggle (UserPreferences.telemetryOptIn) is off by default.
  • Even with opt-in on, the null provider does nothing, so the toggle has no observable effect in v0.15.x. It exists so consent is recorded ahead of any future backend integration.

What gets emitted ​

Already wired call sites (every one is gated by the opt-in):

Event typeTrigger
app.openedBoot, after telemetry init
app.errorTop-level ErrorBoundary catches an exception
project.openedActive project loads (storage or .mstack import)
project.saved.mstack written to disk
project.exportedAny export completes (PNG / sheet / GIF / JSON / mstack / upscaled-png)
tool.activatedUser picks a tool
export.completedPNG / sheet / GIF / JSON / upscale finishes (with duration when measured)
backup.createdAuto or manual backup snapshot
backup.restoredA backup is restored
autotile.generatedAuto-tile-47 dialog Generate button (multi-source flag included)
upscale.runxBR or Nearest upscale runs (algorithm + scale)
plan.changedDev plan override switches

Payloads are strictly aggregate / categorical. Project content (pixels, palette, names) is never transmitted by design.


Privacy posture (for the eventual implementation) ​

  • Off by default. Users opt in via Preferences → Privacy.
  • Identifiers must be anonymous (random uuid persisted in localStorage), never tied to email or hardware fingerprint.
  • Session id is fresh per page-load — never persisted.
  • Events should remain aggregate; never include free-form user input.
  • Telemetry must never crash the app — track() swallows exceptions and warns to the console.

Wiring a real backend (future) ​

ts
import { initTelemetry } from "@/features/telemetry";

class MyProvider implements TelemetryProvider {
  // … see provider.ts contract
}

await initTelemetry(new MyProvider());

setOptIn(false) immediately calls provider.shutdown(), so flipping consent off severs the data flow without a reload.


Motestack is a personal hobby project. The editor and these docs ship under no warranty — back up your `.mstack` files.