SP slotplate
How-to

Analytics events

Instrumenting the FSM without coupling it to a vendor.

src/infrastructure/Analytics.ts is a small interface:

interface Analytics {
  track(event: string, payload?: Record<string, unknown>): void;
}

Swap ConsoleAnalytics for your vendor (Segment, Amplitude, GA4) in composition.ts. Emit events from phase handlers — they're the natural event boundaries.

Where to emit

// SpinPhase.enter
ctx.analytics.track('spin_requested', { bet: ctx.stores.balance.bet });

// WinShowPhase.enter
if (winlines.length > 0) {
  ctx.analytics.track('win_shown', {
    totalWin,
    lineCount: winlines.length,
  });
}

Where NOT to emit

  • Not from presenters. They fire on MobX reactions — too many duplicates.
  • Not from the view. Too deep in the tree — hard to trace causality.
  • Not from stores. Stores should be pure data, no side effects.

What to track

  • Round lifecycle: spin requested, response received, wins shown, round complete.
  • User intent: bet changed, speed changed, skip pressed.
  • Errors: network timeouts, malformed responses, unexpected state transitions.

What NOT to track (client-side)

  • Win amounts per se — the server has the authoritative data.
  • Paytable-derived metrics — you don't have the paytable.
  • RTP — server-side certification.

The client emits user behavior events; the server emits money/outcome events.