Skip to content

feat(frontend): track main navigation section visits in Plausible#13168

Draft
sbpublic wants to merge 15 commits into
mainfrom
impr/frontend/track-nav-section-visits
Draft

feat(frontend): track main navigation section visits in Plausible#13168
sbpublic wants to merge 15 commits into
mainfrom
impr/frontend/track-nav-section-visits

Conversation

@sbpublic

@sbpublic sbpublic commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Motivation

We want to see which of the main navigation sections users actually use and how that shifts over time. Today only Earn emits a section-visit event; Assets, Activity, Explore, Settings (and the Rewards fallback) emit nothing. The Assets sub-tabs also have a default-tab-biased blind spot: view_open fired only on a tab click, so the tab a user lands on was never counted.

This implements the spec docs/ai/spec-driven-development/specs/2026-06-22-impr-track-nav-section-visits.md (authored via the spec-driven workflow), extending the existing Earn PAGE_OPEN pattern to every section and completing the per-tab view counts. It also adds a generic ui_click event for navigation interactions (main nav menu + Assets tab bar) — the complementary "how users navigate" signal alongside page_open's "which sections get visited" count.

Changes

  • Enums (plausible.ts): adds assets-page / activity-page / explore-page / settings-page / rewards-page to PLAUSIBLE_EVENT_VALUES, the matching section PLAUSIBLE_EVENT_CONTEXTS, a new PLAUSIBLE_EVENT_TRIGGERS enum (auto / click), the UI_CLICK event, and a NAVIGATION member on PLAUSIBLE_EVENT_SOURCE_LOCATIONS (the standard source_location enum).
  • Helpers (analytics.services.ts): buildAssetsTabViewEvent() (shared by the click and landing view_open fires) and buildUiClickEvent() (navigation click payloads); plus isAssetsRouteId() in nav.utils.ts (composed from the existing path predicates).
  • Single-route sections: onMount PAGE_OPEN in AllTransactions.svelte (Activity), DappsExplorer.svelte (Explore), Settings.svelte, and Rewards.svelte — mirroring Earn, which is left untouched. A visit counts however the section is reached (nav click, direct URL, back/forward, redirect).
  • Assets section (Assets.svelte): an entry-guarded afterNavigate fires page_open (assets-page) plus a landing view_open (event_trigger = auto) only when arriving from a non-Assets route, so sub-tab switches are not double-counted.
  • Assets sub-tabs (Tabs.svelte): the click view_open is routed through buildAssetsTabViewEvent({ trigger: click }) (preserving the assets_tab / assets_page semantics, adding event_trigger), and now also fires a ui_click (source_sublocation = assets_tabs).
  • Main nav menu (NavigationItem.svelte / NavigationMenuMainItems.svelte): NavigationItem gains an optional trackEvent prop (fired on click, mirroring ExternalLink); each menu item emits ui_click with source_location = navigation, source_sublocation = main_menu, and the section id as event_value.
  • PRODUCT.md: documents the section-visit, Assets sub-tab, and ui_click navigation analytics (updated in this PR, per the workflow).

Tests

  • New specs for Explore, Rewards, Assets, and NavigationItem; added page_open cases to the existing Activity (AllTransactions) and Settings specs.
  • Assets.spec.ts: entry from a non-Assets route (and initial load, from === null) fires page_open + auto view_open; intra-Assets sub-tab switches fire neither; the auto event_value matches the landing tab (parametrised over tokens / nfts / earning).
  • Tabs.spec.ts: a click fires both view_open (event_trigger = click) and ui_click (source_sublocation = assets_tabs).
  • NavigationItem.spec.ts: clicking fires the provided trackEvent; nothing fires when the prop is absent.
  • Unit tests for buildAssetsTabViewEvent (both triggers), buildUiClickEvent (with and without sublocation/value), and isAssetsRouteId (true for tokens/nfts/earning ids, false for the rest and null).
  • Gates: format and lint --max-warnings 0 pass clean. check and the full test suite have only pre-existing, unrelated failures locally (dependency-version skew in untouched sol/ic-pub-key files; the known jsdom/localStorage AllTransactions sessionStorage flake that reproduces on main); both are left to CI.

Divergence from the spec

No material divergence — the implementation follows the spec section by section.

  • Per Implementation §5, the shared buildAssetsTabViewEvent helper hardcodes the view_open event name, so Tabs' generic trackEventName prop now acts purely as an enable-flag (its value no longer sets the emitted event name). The Assets sub-tabs are its only tracked consumer today.
  • The ui_click event was added after a follow-on PM decision and folded into this PR (it deliberately does not add event_trigger to page_open, which stays the complete "visits however reached" metric). It uses the standard source_location key; migrating the legacy location_source on view_open is left as separate, step-by-step cleanup.

🤖 Generated with Claude Code — model: Claude Opus 4.8 (claude-opus-4-8)

sbpublic and others added 15 commits June 22, 2026 15:59
Spec for tracking page_open visits across the five main navigation
sections (Assets, Activity, Earn, Explore, Settings) plus completing the
Assets sub-tab view_open counts with an auto/click event_trigger.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds page-visit event_value/event_context members for the five main nav
sections, the auto/click PLAUSIBLE_EVENT_TRIGGERS enum, and a shared
buildAssetsTabViewEvent factory so the click and landing view_open fires
stay byte-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Composed from the existing isTokensPath/isNftsPath/isEarningPath predicates
to tell "entering the Assets section" from an intra-section sub-tab switch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mirror the existing Earn onMount PAGE_OPEN pattern in each single-route
section's feature component so a section visit is counted however it is
reached (nav click, direct URL, back/forward, redirect).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces the inline view_open object in Tabs.handleClick with
buildAssetsTabViewEvent({ trigger: click }); preserves the existing
assets_tab / assets_page semantics and adds event_trigger.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Entry-guarded afterNavigate fires page_open (assets-page) plus an auto
view_open for the landing tab only when arriving from a non-Assets route,
so sub-tab switches (already counted by Tabs) are not double-counted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…changes

Formatter/linter output only: prettier on the spec + Assets.svelte and
eslint import-order on Settings.svelte / AllTransactions.svelte. No
behaviour change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- page_open on mount for Activity, Explore, Settings, Rewards
- Assets entry-guard: page_open + auto view_open on section entry,
  neither on intra-Assets sub-tab switches, landing tab parametrised
- Tabs click fires view_open with event_trigger=click
- buildAssetsTabViewEvent helper (auto + click payloads)
- isAssetsRouteId true/false cases

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Folds the generic ui_click event (main nav menu + Assets tab bar) into
the existing spec: schema, helper, instrumentation steps, tests,
acceptance, and out-of-scope (orthogonal to page_open; standard
source_location key; legacy location_source migration deferred).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the generic UI_CLICK event and a NAVIGATION source_location member
(standard source_location key), plus a buildUiClickEvent factory so
navigation click payloads stay centralised and consistent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds an optional trackEvent prop to NavigationItem (fired on click,
mirroring ExternalLink) and wires each main-menu item to a ui_click with
source_location=navigation, source_sublocation=main_menu, and the
section id as event_value.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A sub-tab click now fires the generic ui_click (source_sublocation=
assets_tabs) alongside the existing view_open(trigger=click); the two
are complementary UI-interaction and appearance signals.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- buildUiClickEvent payloads (with and without sublocation/value)
- NavigationItem fires/omits trackEvent on click per prop presence
- Tabs click fires both view_open(click) and ui_click

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant