Skip to content

feat(analytics): instrument 4-stage Plausible funnel (Input -> Conversion -> Export) - #226

Merged
obvious-autobuild-staging[bot] merged 1 commit into
masterfrom
feat/plausible-funnel-events
Oct 19, 2026
Merged

obvious-autobuild-staging[bot] merged 1 commit into
masterfrom
feat/plausible-funnel-events

Conversation

@obvious-autobuild-staging

Copy link
Copy Markdown
Contributor

Why

Previously, CSVJSON's analytics funnel had four blind spots between page landing and output egress:

  1. Conversion only fired when isValid(direction, text) === true, so malformed pastes or uploads emitted zero events — making it impossible to separate visitors who never provided data from visitors whose data failed parsing.
  2. Clicking Try an example called tracker.edit(...) (tagging sample clicks as input: "paste"), while clicking the direction switch (handleFlip) emitted no tracker event at all.
  3. Export emitted only { via, format }, conflating Input-pane copies/downloads with Output-pane egress.
  4. Power-user keyboard copies (Cmd/Ctrl+C inside the JSON output editor) and grid selection copies (Copy as CSV chip or Cmd/Ctrl+C in CsvTable) never triggered trackExport.

What

Implements AC-10 and Locked Decision D9 from Blueprint art_MJHTha6X and Plausible runbook art_vUXl76He:

Funnel Stage Plausible Goal / gtag Event Properties Trigger
1. Visit pageview — Initial mount (script.manual.js)
2. Data Provided Input / input direction, input (paste | file | drag | permalink | example | flip), size, valid (boolean) Settled or discrete non-empty data provision (even when valid === false), deduplicated by signature & 2s window
3. Valid Output Conversion / conversion direction, input, size When provided data produces valid conversion output (valid === true) — 100% backward-compatible with existing goal
4. Egress Export / export via (copy | download), format (json | csv), pane (output | input), direction Header Copy/Download buttons, CsvTable selection copy (Copy as CSV chip + Cmd/Ctrl+C), and native Cmd/Ctrl+C inside OutputPane

Tradeoffs

  • Separate Input deduplication state vs. shared Conversion state: createConversionTracker tracks lastInputSignature and lastInputFiredAt separately from lastSignature/lastFiredAt so an invalid input records Input (valid: false) without burning the Conversion window when the user subsequently fixes the syntax error.
  • Backward-compatible ExportProps: pane and direction are optional on ExportProps and omitted when undefined so existing minimal callers continue to work unchanged while App.tsx supplies full { via, format, pane, direction } context on every egress path.
  • Visual evidence exception: This PR is pure analytics instrumentation (no visual UI or layout changes); verified via Vitest unit and component integration suites plus verify-seo.sh.

How to Review

  • app/src/analytics/events.ts — InputProps, trackInput, expanded ConversionInput (example, flip), ExportProps (pane, direction), and 2-stage attemptFire in createConversionTracker.
  • app/src/App.tsx — onTryExample (tracker.discrete(..., "example", sample)), handleFlip (tracker.discrete(..., "flip", nextInput)), enriched trackExport calls, and tracker cleanup on unmount.
  • app/src/components/CsvTable.tsx, app/src/components/InputPane.tsx, app/src/components/OutputPane.tsx — onCopySelection and onNativeCopy wiring.
  • app/src/analytics/events.test.ts & app/src/App.test.tsx — unit and end-to-end component tests across all 4 funnel stages.

Verification

  • cd app && npm run lint && npx tsc -b --noEmit && npm test (30 test files, 525 tests passing)
  • cd app && npm run build (app/dist rebuilt and committed in parity)
  • bash .github/scripts/verify-seo.sh (passed)

Human author: David Boskovic ([email protected])

🔗 Obvious Project · 🧵 Obvious Thread · 🔀 Obvious PR Artifact

…sion -> Export)

- Emit Stage 2 `Input` (`input` on gtag, `Input` on Plausible) with `{ direction, input, size, valid }` on settled and discrete non-empty data provision (even when `valid === false`), while keeping `Conversion` strictly gated on `valid === true`.
- Separate `Try an example` (`input: "example"`) and direction switches (`input: "flip"`) from clipboard pastes (`input: "paste"`).
- Enrich `Export` with `pane: "output" | "input"` and `direction: "csv_to_json" | "json_to_csv"`, and track `CsvTable` selection copies (`Copy as CSV` chip + `Cmd/Ctrl+C`) and native `Cmd/Ctrl+C` copies inside `OutputPane`.
- Expand unit and integration tests in `events.test.ts` and `App.test.tsx` and rebuild `app/dist`.

Co-authored-by: David Boskovic <[email protected]>
@obvious-autobuild-staging
obvious-autobuild-staging Bot marked this pull request as ready for review October 19, 2026 05:09
@obvious-autobuild-staging
obvious-autobuild-staging Bot merged commit 57aebbc into master Oct 19, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants