Bonds Analytics Catalog

Comprehensive reference for all Mixpanel tracking in the Bonds app. Module: src/utils/analytics.js.

For product: This document lists every event, property, user attribute, and funnel tracked in the app. Use the table of contents to navigate.

For developers: When adding or changing events, update this document in the same PR. See the Developer Checklist at the bottom.


Table of Contents

  1. Conventions
  2. Identity & Properties
  3. Screens
  4. Domain Events
  5. Element Clicked Reference
  6. Funnels
  7. Recommended Mixpanel Reports
  8. Developer Checklist

1. Conventions

Naming Rules

What Convention Example
Event names Title Case, Object-Action, past tense Simulator Session Completed
Property names snake_case chapter_index, skill_level
Screen names lowercase, underscore-separated learn_video, simulator_results

When to Use Which Event Type

Pattern When to use Example
Domain event (own name) Funnel steps, business-critical actions Onboarding Completed, Daily Question Voted
Screen Viewed A distinct screen becomes visible Screen Viewed { screen: 'journey' }
Element Clicked UI interaction (button, tab, card, toggle) Element Clicked { screen: 'profile', element: 'invite_partner' }

Property Value Enums

Property Possible values
platform ios, android, web
user_type anonymous, authenticated
step_type learn, practice, insight, act
mode freeform, journey
input_mode (simulator) voice, text
method (auth) google, apple, email
element_type button, tab, banner, card, toggle, link
delivery (report) clipboard, slack

2. Identity & Properties

2a. Identity Lifecycle

┌─────────────────┐     identifyUser()      ┌──────────────────┐
│    Anonymous     │ ─────────────────────→  │   Authenticated  │
│  (random ID)     │                         │  (Bubble user ID) │
│  user_type:      │                         │  user_type:       │
│   'anonymous'    │     resetIdentity()     │   'authenticated' │
│                  │ ←─────────────────────  │                   │
└─────────────────┘                          └──────────────────┘
Stage Trigger What happens
App opens, no auth initAnalytics() Anonymous distinct_id assigned, super props registered
User authenticates identifyUser(userId, traits) via UserContext identify(userId) merges anonymous→identified, people props set
User logs out resetIdentity() reset() clears identity, back to anonymous with fresh ID

2b. Super Properties

Auto-attached to every event. Set by initAnalytics(), updated by identifyUser().

Property Type Example Description
app_version string v1.0.0-alpha-bc22c80df36e Build version with content hash
platform string ios Detected from window.natively (ios / android / web)
user_type string authenticated anonymous until first identifyUser(), then authenticated

2c. People Properties (User Profile)

Stored on the Mixpanel user profile. Visible in the People section.

Property Type Example Set by When updated
$name string "Sarah" identifyUser() First auth only
$email string "sarah@example.com" identifyUser() First auth only
coins number 150 identifyUser() + setUserProperties() Every setUserData call
partner_connected boolean true identifyUser() + setUserProperties() Every setUserData call
partner_name_collected boolean true setUserProperties() Every setUserData call where partnerName is present
partner_gender string "female" setUserProperties() Every setUserData call where partnerGender is present
onboarding_complete boolean true identifyUser() First auth only
signup_date string (ISO) "2026-01-15T10:30:00Z" set_once First auth ever (never overwritten)
initial_source string "Ross2" set_once via identifyUser() First auth ever (never overwritten)
initial_utm_source string "Facebook" set_once via identifyUser() First auth ever (never overwritten)
initial_utm_medium string "Paid" set_once via identifyUser() First auth ever (never overwritten)
initial_utm_campaign string "Default_Campaign" set_once via identifyUser() First auth ever (never overwritten)
initial_through string "partner-x" set_once via identifyUser() First auth ever (never overwritten)
last_source string "Ross2" set via identifyUser() / captureAttribution() Every new campaign click
last_utm_source string "Facebook" set via identifyUser() / captureAttribution() Every new campaign click
last_utm_medium string "Paid" set via identifyUser() / captureAttribution() Every new campaign click
last_utm_campaign string "Default_Campaign" set via identifyUser() / captureAttribution() Every new campaign click
last_through string "partner-x" set via identifyUser() / captureAttribution() Every new campaign click
is_subscribed boolean true setUserProperties() via EntitlementContext Every entitlement refresh (auth, foreground, post-purchase, post-restore)
subscription_type string | null "quarterly" setUserProperties() via EntitlementContext Every entitlement refresh — RevenueCat-derived (yearly/quarterly/monthly), null when not subscribed
payment_variant string "B" setUserProperties() via <PaymentVariantSeeder> When Bubble reports the variant, or on a fresh Statsig seed

Cohort tag: the A/B/C payments cohort's source of truth is the Bubble User field payment_variant (Statsig only seeds it once — see docs/statsig-experiments.md). It's written to the Mixpanel user profile as the payment_variant People property (the effective value incl. admin overrides, set by <PaymentVariantSeeder>) — use this for all cohort filtering and breakdowns. It's a People (not super) property because the cohort is sticky and server-owned: a profile property survives reset(), is queryable on the user level, and is still segmentable in event reports, with no need for an at-event snapshot. The raw Statsig bucket is not mirrored to Mixpanel as experiment_payments (kept to one property to avoid confusion); Statsig retains the exposure for experiment analysis on its side.


3. Screens

All values used with Screen Viewed. Fired via screen(name) helper which calls track('Screen Viewed', { screen: name }).

Screen When shown Source Notes
welcome App loads without active session App.jsx
signin User taps "Sign In" App.jsx
signup After onboarding insight, before account creation App.jsx
onboarding_intro One-time intro video before questions App.jsx
onboarding User starts or resumes onboarding App.jsx
onboarding_insight During insight generation/playback App.jsx
journey Journey tab selected MainTabs.jsx
simulator Simulator tab selected MainTabs.jsx
fun Fun Zone tab selected MainTabs.jsx
profile Profile tab selected MainTabs.jsx
step_review User opens a completed step for review StepReview.jsx Extra props: step_type, chapter
ftue_walkthrough First-time user walkthrough starts MainTabs.jsx
daily_question Daily question overlay opened DailyQuestion.jsx
push_prompt Push notification permission dialog shown MainTabs.jsx
name_prompt Name entry dialog after signup MainTabs.jsx
partner_name_prompt Partner name entry dialog (after user name dialog) MainTabs.jsx
account_info Account info / danger zone screen MainTabs.jsx
share_viewer Shared content viewer (external link) ShareViewer.jsx

4. Domain Events

App Lifecycle

App Opened

Fires once on app launch after analytics initialization.

Property Type Example Required
(none)

Source: App.jsx

App Backgrounded

Fires when the app moves to the background (Natively lifecycle hook).

Property Type Example Required
(none)

Source: App.jsx

App Foregrounded

Fires when the app returns to the foreground (Natively lifecycle hook).

Property Type Example Required
(none)

Source: App.jsx

Logged Out

Fires when user logs out. Identity is reset after this event.

Property Type Example Required
(none)

Source: App.jsx

Session Force Logout

Fires when Bubble force-logs the user out via setLoginState(false) while they were in an authenticated phase (no React-initiated logout pending). Most likely cause is the WebView losing its session cookie (_u2main) across a process restart, which triggers Bubble's "User is logged out" event server-side. Tracked into Mixpanel so we can monitor frequency and surface in retention/funnels alongside other auth events.

Property Type Example Required
phase string "main" yes
source string "bubble" yes

Source: App.jsx (in setLoginState(false) handler when source === 'bubble')

Fires when a deep link is processed. Attribution params (if present in the URL) are spread into the event properties.

Property Type Example Required
tab string | null "journey" no
view string | null "chapter_1" no
step_status string | undefined "completed" no
source string "Ross2" no (from attribution)
utm_source string "Facebook" no (from attribution)
utm_medium string "Paid" no (from attribution)
utm_campaign string "Default_Campaign" no (from attribution)
through string "partner-x" no (from attribution)

Source: MainTabs.jsx

Attribution Captured

Fires when a URL with attribution params is opened (cold start or warm start), regardless of whether a deep link route is present. Independent of Deep Link Opened.

Property Type Example Required
source string "Ross2" no
through string "partner-x" no
utm_source string "Facebook" no
utm_medium string "Paid" no
utm_campaign string "Default_Campaign" no

Source: analytics.js via captureAttribution()


Authentication

Sign In Started

Fires when user initiates sign-in (OAuth or email).

Property Type Example Required
method string "google" / "apple" / "email" yes

Source: SignInScreen.jsx

Sign In Completed

Fires on first successful identity merge (anonymous → authenticated). Reads bonds_auth_method from localStorage to detect email auth; defaults to "oauth" for SSO.

Property Type Example Required
method string "google" / "apple" / "email" / "oauth" yes

Source: UserContext.jsx

Sign In Failed

Fires when sign-in fails (wrong password, Bubble error).

Property Type Example Required
error string "wrong_password" / "not_found" yes

Source: App.jsx (via setSignInError)

Sign In Blocked

Fires when sign-in detects a non-existing account (UID comparison or Bubble search).

Property Type Example Required
reason string "account_not_found" yes

Source: App.jsx (via onSigninComplete)


Onboarding

Onboarding Step Completed

Fires after each onboarding question is answered.

Property Type Example Required
step number 2 yes
question_id string "comm_style" yes
type string "single-select" / "slider" / "multi-select" / "open-question" yes
answer_value string "Direct" yes
partner_gender string|null "female" / "male" / "other" / null step 0 only — partner gender follow-up

Source: OnboardingFlow.jsx

Onboarding Completed

Fires when user finishes all onboarding steps.

Property Type Example Required
total_steps number 12 yes
coins number 12 yes
loveLanguage string "Words of Affirmation" no
partnerLoveLanguage string "Physical Touch" no
skippedTiebreaker boolean true no
partner_gender string|null "female" / "male" / "other" / null no

Source: OnboardingFlow.jsx

Onboarding Abandoned

Fires when user exits onboarding via back button on step 0.

Property Type Example Required
(none)

Source: App.jsx

Onboarding Resumed

Fires when onboarding session is resumed, either automatically on app reload (source: 'auto') or when user chooses to continue via the resume dialog (source: 'dialog').

Property Type Example Required
phase string "questions" / "signup" / "insight" yes
step number/string 5 / "signup" / "insight" yes
source string "auto" / "dialog" yes

Source: App.jsx

Onboarding Intro Viewed

Fires when the one-time intro video screen is mounted.

Property Type Example Required
(none)

Source: OnboardingIntro.jsx

Onboarding Intro Completed

Fires when user taps the CTA after the intro video has finished playing.

Property Type Example Required
(none)

Source: OnboardingIntro.jsx

Onboarding Intro Skipped

Fires when user taps the CTA before the intro video finishes (skips remaining video).

Property Type Example Required
(none)

Source: OnboardingIntro.jsx

Onboarding Intro Replayed

Fires when user taps replay to watch the intro video again.

Property Type Example Required
(none)

Source: OnboardingIntro.jsx

Onboarding Intro Backed Out

Fires when user navigates back from the intro screen to welcome.

Property Type Example Required
(none)

Source: OnboardingIntro.jsx

Two Last Questions Shown

Fires when the "Two last questions" popup appears just before the first open question (Groups A & C only — gated by useOnboardingCoinsHidden()). PRD UI Outputs #2. The CTA emits Element Clicked { screen: 'onboarding', element: 'two_last_questions_continue' }.

Property Type Example Required
(none)

Source: OnboardingFlow.jsx

Onboarding Insight Started

Fires when insight generation begins after all questions answered.

Property Type Example Required
(none)

Source: OnboardingInsight.jsx

Onboarding Insight Generated

Fires when insight data is received from Bubble.

Property Type Example Required
insight_id string "ins_abc123" yes

Source: OnboardingInsight.jsx

Onboarding Insight Prewatch Shown

Fires when the before-watching screen appears ("This insight usually uses 3 coins, but this one's on us" for Groups A & C; coin line hidden for Group B). PRD UI Outputs #4.

Property Type Example Required
(none)

Source: OnboardingInsight.jsx

Onboarding Insight Watch Tapped

Fires when the user taps "Watch" on the before-watching screen, starting insight playback.

Property Type Example Required
(none)

Source: OnboardingInsight.jsx

Onboarding Insight Playback Completed

Fires when TTS playback finishes and user taps Continue.

Property Type Example Required
(none)

Source: OnboardingInsight.jsx

Onboarding Insight Playback Skipped

Fires when user taps Continue before TTS playback finishes.

Property Type Example Required
(none)

Source: OnboardingInsight.jsx

Onboarding Insight CTA Tapped

Fires when user taps "Create Your Account" after insight playback.

Property Type Example Required
(none)

Source: OnboardingInsight.jsx

Onboarding Insight Timed Out

Fires when insight generation exceeds the 90s timeout.

Property Type Example Required
(none)

Source: OnboardingInsight.jsx

Onboarding Data Connected

Fires after signup when onboarding data is sent to Bubble for the new user.

Property Type Example Required
coins number 10 yes
answer_count number 10 yes
insight_id string "ins_abc123" yes

Source: App.jsx

Onboarding Step Back

Fires when user navigates backward during onboarding.

Property Type Example Required
from_step number 8 yes
to_step number 7 yes

Source: OnboardingFlow.jsx

Onboarding Mic Permission Denied

Fires when microphone permission is denied during onboarding open question.

Property Type Example Required
(none)

Source: OpenQuestion.jsx

Onboarding Mic Unavailable

Fires when microphone/speech recognition is unavailable for a non-permission reason.

Property Type Example Required
reason string "network" / "no_api" yes

Source: OpenQuestion.jsx

Onboarding Speech API Unavailable

Fires when SpeechRecognition API doesn't exist on the device and dialog auto-switches to text mode.

Property Type Example Required
(none)

Source: InsightOtherDialog.jsx


Signup

Sign Up Started

Fires when user initiates sign-up (OAuth or email).

Property Type Example Required
method string "google" / "apple" / "email" yes

Source: SignUpScreen.jsx

Sign Up Completed

Fires on successful signup. Detects email vs OAuth via bonds_auth_method localStorage flag.

Property Type Example Required
method string "email" / "oauth" yes

Source: App.jsx

Sign Up Failed

Fires when sign-up fails (Bubble error).

Property Type Example Required
error string "already_exists" yes

Source: App.jsx (via setSignUpError)

Sign Up Blocked

Fires when sign-up detects an existing account (UID comparison or Bubble search).

Property Type Example Required
reason string "existing_account" yes

Source: App.jsx (via onSignupComplete)


Email Authentication

Email OTP Sent

Fires when an OTP code is successfully sent to the user's email.

Property Type Example Required
flow string "signup" / "forgot" yes

Source: SignUpScreen.jsx, SignInScreen.jsx

Email OTP Verified

Fires when user successfully verifies the OTP code.

Property Type Example Required
flow string "signup" / "forgot" yes

Source: SignUpScreen.jsx, SignInScreen.jsx

Email OTP Failed

Fires when OTP verification fails (wrong or expired code).

Property Type Example Required
flow string "signup" / "forgot" yes
error string "invalid" / "expired" yes

Source: SignUpScreen.jsx, SignInScreen.jsx

Email OTP Resent

Fires when user taps resend code.

Property Type Example Required
flow string "signup" / "forgot" yes

Source: SignUpScreen.jsx, SignInScreen.jsx

Password Reset Completed

Fires after a successful password reset + auto sign-in.

Source: SignInScreen.jsx


Sharing

Share Created

Fires when user creates a shareable link.

Property Type Example Required
content_type string "insight" / "simulator_results" / "activity" yes
content_id string "abc123" yes

Source: InsightPlayback.jsx, SimulatorResults.jsx, ActivityView.jsx

Share Viewed

Fires when someone views a shared link.

Property Type Example Required
content_type string "insight" / "simulator_results" / "activity" yes
content_id string "abc123" yes

Source: ShareViewer.jsx


Account

Account Deleted

Fires when user confirms account deletion.

Source: MainTabs.jsx (AccountInfoPage)

Onboarding Question Skipped

Fires when user skips an open-ended onboarding question.

Property Type Example Required
question string "What do you wish your partner would do more of" yes

Source: OpenQuestion.jsx


Journey

Chapter numbering convention. Two property names coexist for historical reasons, both 1-based:

They agree numerically. When building a funnel across both groups, Mixpanel's "formula" column can alias one to the other.

dynamic segmentation. Every chapter-scoped event carries a boolean dynamic property (Phase 2 dynamic chapters vs predefined). Use it to split funnels and retention by chapter kind. Predefined chapters report dynamic: false; LLM-generated 3-node chapters report dynamic: true. For Simulator Session * events the property is present only when mode === 'journey'.

Chapter Started

Fires when the user pays the chapter cost (10 coins per the Coin Economy price card) via the coin gate and a new chapter begins. Not tied to a specific step — mirrors Chapter Completed.

Property Type Example Required
chapter number 0 yes
chapter_title string "Active Listening" yes
coin_cost number 10 yes
dynamic boolean false yes

Source: JourneyPath.jsx

Journey Step Started

Fires when a journey step begins (learn, practice, insight, or act).

Property Type Example Required
step_type string "learn" yes
chapter number 0 yes
chapter_title string "Active Listening" yes
dynamic boolean false yes

Source: ChapterFlow.jsx

Journey Step Completed

Fires when a journey step finishes successfully.

Property Type Example Required
step_type string "practice" yes
chapter number 0 yes
coins number 3 yes
replay boolean false yes
dynamic boolean false yes

Source: ChapterFlow.jsx

Journey Step Abandoned

Fires when user exits a journey step without completing it.

Property Type Example Required
step_type string "learn" yes
chapter number 0 yes
dynamic boolean false yes

Source: ChapterFlow.jsx

Journey Video Watched

Fires when the learn video finishes playing.

Property Type Example Required
chapter number 0 yes
dynamic boolean false yes

Source: LearnStep.jsx

Journey Practice Started

Fires when user starts a practice simulator session from the journey.

Property Type Example Required
chapter number 0 yes
dynamic boolean false yes

Source: PracticeStep.jsx

Journey Practice Completed

Fires when practice simulator session ends with a score.

Property Type Example Required
chapter number 0 yes
score number 4 yes
coins number 3 yes
attempt number 1 yes
dynamic boolean false yes

Source: PracticeStep.jsx

Chapter Completed

Fires when all steps in a chapter are done.

Property Type Example Required
chapter number 0 yes
chapter_title string "Active Listening" yes
dynamic boolean false yes

Source: ChapterFlow.jsx

Chapter Start Tapped

Fires when the user taps the external "START CHAPTER · N COINS" button on the journey map. This button replaces the in-bubble START for the first step of a chapter (PRD Phase 1, page 2).

Property Type Example Required
screen string "journey_map" yes
chapter_number number 1 yes
via string "external_cta" yes
step_type string "learn" yes
dynamic boolean false yes

Source: JourneyScreen.jsx

Chapter Step Start Tapped

Fires when the user taps the in-bubble START button on a non-first step (Practice/Insight/Act) on the journey map.

Property Type Example Required
screen string "journey_map" yes
chapter_number number 1 yes
via string "bubble" yes
step_type string "practice" / "insight" / "act" yes
dynamic boolean false yes

Source: JourneyScreen.jsx

Chapter Paused State Shown

Fires when the paused view is rendered the day after a chapter is completed (PRD Phase 1, page 4). Deduped by completed → next pair so a single paused session fires the event once.

Property Type Example Required
screen string "chapter_paused" yes
next_chapter_number number 2 yes
completed_chapter_number number 1 yes
dynamic boolean false yes

Source: JourneyScreen.jsx

Chapter Confirmation Shown

Fires when a predefined confirmation card is shown. Two sources — when building the Confirmation → Start → Complete funnel, union screen ∈ { ch1_predefined_confirmation, chapter_predefined_confirmation }:

Property Type Example Required Notes
screen string "ch1_predefined_confirmation" | "chapter_predefined_confirmation" yes
step number 4 Ch1 only FTUE step index
chapter_number number 1, 2, 3 yes
chapter_id string "1776754765374x…" Ch2/Ch3 Bubble chapter id
chapter_title string "Slowing the Reaction" Ch2/Ch3
is_replay boolean false Ch1 only
dynamic boolean false yes chapter kind (Phase 2)

Source: DrLeoWalkthrough.jsx (Ch1), JourneyPath.jsx (Ch2 / Ch3).

Chapter Confirmation Accepted

Fires when the user taps "Start Chapter" on the predefined confirmation card (Ch1 FTUE or Ch2/Ch3 standalone sheet).

Property Type Example Required Notes
screen string "ch1_predefined_confirmation" | "chapter_predefined_confirmation" yes
chapter_number number 1, 2, 3 yes
chapter_id string "1776754765374x…" Ch2/Ch3
chapter_title string "Slowing the Reaction" Ch2/Ch3
via string "start_chapter" yes
dynamic boolean false yes chapter kind (Phase 2)

Source: DrLeoWalkthrough.jsx (Ch1), JourneyPath.jsx (Ch2 / Ch3).

Chapter Confirmation Dismissed

Fires when the user taps "No thanks, later" on the predefined confirmation card.

Property Type Example Required Notes
screen string "ch1_predefined_confirmation" | "chapter_predefined_confirmation" yes
chapter_number number 1, 2, 3 yes
chapter_id string "1776754765374x…" Ch2/Ch3
chapter_title string "Slowing the Reaction" Ch2/Ch3
via string "no_thanks_later" yes
dynamic boolean false yes chapter kind (Phase 2)

Source: DrLeoWalkthrough.jsx (Ch1), JourneyPath.jsx (Ch2 / Ch3).

FTUE First Slide Shown

Fires when the FTUE first slide ("Generating your chapter…") is shown (PRD Phase 1, page 5).

Property Type Example Required
screen string "ftue_first_slide" yes
step number 0 yes
is_replay boolean false yes

Source: DrLeoWalkthrough.jsx

FTUE Skipped

Fires when the user taps Skip on any FTUE step. Per PRD §6, Skip now jumps to the last FTUE step instead of closing the walkthrough.

Property Type Example Required
screen string "ftue_first_slide" | "ftue_walkthrough" yes
step number 0 yes
is_replay boolean false yes

Source: DrLeoWalkthrough.jsx

Chapter Menu Opened

Fires on the OPEN transition of the chapter-list dropdown (chevron tap when the menu was closed). Does not fire on close — use the companion Element Clicked { element: 'chapter_menu_chevron' } event for bi-directional tap counts.

Property Type Example Required Notes
screen string "journey_map" yes
chapter_number number 2 yes focal chapter at the moment of tap (1-based)
chapter_id string "1776754765374x…" yes Bubble chapter id
dynamic boolean false yes focal chapter's kind

Source: JourneyScreen.jsx

Chapter Menu Chapter Selected

Fires when the user picks a chapter from the chapter-list dropdown. Funnels dropdown engagement → scroll navigation.

Property Type Example Required Notes
screen string "journey_map" yes
from_chapter_number number 1 yes 1-based; the user's active chapter at tap time
to_chapter_number number 3 yes 1-based; the chapter they picked
to_chapter_id string "1776754765374x…" yes
to_chapter_title string "Slowing the Reaction" yes
dynamic boolean false yes target chapter's kind

Source: JourneyPath.jsx


Insight

Insight Flow Started

Fires when an insight generation flow begins.

Property Type Example Required
type string "learn" / "activity" / "journey" yes
learn_type_id string "lt_01" when type=learn
activity_id string "act_01" when type=activity
chapter number 0 when type=journey
replay boolean false when type=journey
dynamic boolean false when type=journey

Source: InsightFlow.jsx · InsightStep.jsx

Insight Question Answered

Fires per insight question response.

Property Type Example Required
answer string "yes" / "no" / custom text yes

Source: InsightFlow.jsx · InsightStep.jsx

Insight Generated

Fires when all insight questions are answered and generation is triggered. Currently only fires for type: 'learn'.

Property Type Example Required
type string "learn" yes
learn_type_id string "lt_01" yes

Source: InsightFlow.jsx

Insight Generation Timed Out

Fires when insight generation exceeds the timeout.

Property Type Example Required
type string "learn" / "activity" / "journey" yes
learn_type_id string "lt_01" when type=learn (always sent, may be null)
activity_id string "act_01" when type=activity (always sent, may be null)
chapter number 0 when type=journey
dynamic boolean false when type=journey

Source: InsightFlow.jsx (learn/activity) · InsightStep.jsx (journey)

Insight Playback Completed

Fires when TTS playback finishes and user taps Continue.

Property Type Example Required
(none)

Source: InsightFlow.jsx · InsightStep.jsx

Insight Playback Skipped

Fires when user taps Continue before TTS playback finishes.

Property Type Example Required
(none)

Source: InsightFlow.jsx · InsightStep.jsx

Insight Flow Closed

Fires when user exits the insight flow without completing playback.

Property Type Example Required
(none)

Source: InsightFlow.jsx


Simulator

Simulator Session Started

Fires when a simulator session begins (freeform or journey practice).

Property Type Example Required
mode string "journey" / "freeform" yes
input_mode string "voice" / "text" yes
chapter_id string "ch_01" when mode=journey
dynamic boolean false when mode=journey

Source: SimulatorSection.jsx

Simulator Session Completed

Fires when AI evaluation is received and results are shown.

Property Type Example Required
score number 4 yes
skill_level string "Finding Your Groove" yes
mode string "journey" / "freeform" yes
input_mode string "voice" / "text" yes
chapter_id string "ch_01" when mode=journey
dynamic boolean false when mode=journey

Source: SimulatorSection.jsx

Simulator Session Closed

Fires when user manually ends a session (via close dialog).

Property Type Example Required
mode string "journey" / "freeform" yes
input_mode string "voice" / "text" yes
chapter_id string "ch_01" when mode=journey
dynamic boolean false when mode=journey

Source: SimulatorSection.jsx

Simulator Session Retried

Fires when user retries the session from the results screen.

Property Type Example Required
mode string "journey" / "freeform" yes
input_mode string "voice" / "text" yes
chapter_id string "ch_01" when mode=journey
dynamic boolean false when mode=journey

Source: SimulatorSection.jsx

Simulator Session Error

Fires on unrecoverable session error. For the JSON-extraction boundaries (Stage 1, Stage 3), this only fires after parse retries are exhausted — see Simulator Issue Retry / Simulator Eval Retry below for the per-attempt signal.

Property Type Example Required
code string "TIMEOUT" / "EVAL_PARSE_FAILED" / "ISSUE_PARSE_FAILED" / "UNKNOWN" yes
message string "Connection lost" yes
mode string "journey" / "freeform" yes
input_mode string "voice" / "text" yes
chapter_id string "ch_01" when mode=journey
dynamic boolean false when mode=journey

Source: SimulatorSection.jsx

Simulator Eval Retry

Fires per attempt when the Stage 3 evaluation JSON fails to parse and we re-fire the silent response.create on the same session. After today's tool-calling change this should be near-zero in production — the model is structurally forced into schema-valid JSON. Kept as belt-and-suspenders.

Property Type Example Required
attempt number 1 yes
max_retries number 2 yes
raw_length number 412 yes
raw_text_hash string "a3f1b29c" (FNV-1a fingerprint of raw response, no PII) yes
mode string "journey" / "freeform" yes
chapter_id string "ch_01" when mode=journey
dynamic boolean false when mode=journey

Source: SimulatorSection.jsx

Simulator Eval Retry Recovered

Fires once when a Stage 3 eval succeeds after at least one retry. Lets analytics distinguish first-try clean sessions from "drift caught and recovered" sessions, both of which otherwise look identical at Simulator Session Completed.

Property Type Example Required
attempts_total number 2 (1 retry + final success = 2) yes
mode string "journey" / "freeform" yes
chapter_id string "ch_01" when mode=journey
dynamic boolean false when mode=journey

Source: SimulatorSection.jsx

Simulator Issue Retry

Stage 1 (issue-extraction) counterpart to Simulator Eval Retry. Same shape, same near-zero post-tool-call expectation.

Property Type Example Required
attempt number 1 yes
max_retries number 2 yes
raw_length number 188 yes
raw_text_hash string "7e22c014" yes
mode string "journey" / "freeform" yes
chapter_id string "ch_01" when mode=journey
dynamic boolean false when mode=journey

Source: SimulatorSection.jsx

Simulator Issue Retry Recovered

Stage 1 counterpart to Simulator Eval Retry Recovered.

Property Type Example Required
attempts_total number 2 (1 retry + final success = 2) yes
mode string "journey" / "freeform" yes
chapter_id string "ch_01" when mode=journey
dynamic boolean false when mode=journey

Source: SimulatorSection.jsx

Coins Deducted

Fires when coins are spent to unlock stage 2 of a freeform simulator session.

Property Type Example Required
amount number 8 yes
context string "simulator" yes

Source: SimulatorSection.jsx

Coins Gifted

Fires when the user receives a one-time coin gift (e.g. from the "Not Enough Coins" dialog).

Property Type Example Required
amount number 3 yes
previousBalance number 0 yes

Source: NotEnoughCoinsDialog.jsx


Activities

Activity Create Started

Fires when user initiates creating a new activity.

Property Type Example Required
act_type_id string "affirmation" yes

Source: ActivityView.jsx

Activity View Completed

Fires when user finishes viewing/listening to an activity.

Property Type Example Required
activity_id string "act_abc123" yes
replay boolean false yes

Source: ActivityView.jsx

Activity View Closed

Fires when user closes an activity without completing it.

Property Type Example Required
(none)

Source: ActivityView.jsx


Daily Question

Daily Question Viewed

Fires when the daily question appears on screen.

Property Type Example Required
question_id string "dq_20260318" yes
category string "intimacy" yes

Source: DailyQuestion.jsx

Daily Question Voted

Fires when user selects an answer.

Property Type Example Required
question_id string "dq_20260318" yes
index number 1 yes

Source: DailyQuestion.jsx


Partner

Partner Connected

Fires when a partner is connected for the first time (partner_connected transitions false → true).

Property Type Example Required
(none)

Source: UserContext.jsx


Payments

All payment events run on the React side via the Natively RevenueCat bridge and a direct RC REST read for entitlement state — Bubble is uninvolved.

Removed: Paywall Viewed / Paywall Dismissed — these only fired from RC's hosted paywall (EntitlementContext.showPaywall()), which has been removed. The app uses a single custom paywall (PlansScreen), tracked via Plans Screen Shown (see below).

Purchase Started

Fires when buy(packageId) is called.

Purchase Completed

Fires when the purchasePackage callback returns status: 'SUCCESS'.

Purchase Failed

Fires when the purchasePackage callback returns a non-SUCCESS status.

Purchase Restore Tapped

Fires when the user taps Restore Purchases.

Purchase Restore Completed

Fires after the post-restore entitlement refresh.

Plans screen events

Custom in-app paywall at PlansScreen.jsx. Pushed from Profile → Subscription.

Purchase Started/Purchase Completed/Purchase Failed/Purchase Restore Tapped/Purchase Restore Completed already fire from EntitlementContext.buy/restore; the plans screen passes source: 'plans_screen' so the funnel can be segmented by entry point.

Entitlement Changed

Fires whenever isSubscribed flips on EntitlementContext (renewal, expiry, cross-device sync).

Also: is_subscribed is set as a Mixpanel People property every time EntitlementContext resolves, so the latest known state lives on the user profile for funnel segmentation.

Cohort coin-gate events

Fired by the shared useCoinGate hook (src/hooks/useCoinGate.js), which funnels every coin-spending action (chapter start, simulator session, activity creation, etc.) through one cohort-aware path. Replaces the legacy local if (coins < N) checks scattered across feature files.

Cohort ('A' | 'B' | 'C') is not encoded on these events — it lives on the Mixpanel user profile as the payment_variant People property (the effective value incl. admin overrides, set by <PaymentVariantSeeder>). Segment/break down any coin-gate event by payment_variant for cohort funnels. (The raw Statsig bucket is intentionally not mirrored to Mixpanel — Statsig keeps the exposure for experiment analysis.)

What these events add instead is gate_outcomewhich branch the gate took, orthogonal to cohort:

Premium-user surfaces

Subscription lifecycle screens

People + super properties

subscription_type is pushed as a Mixpanel People property by EntitlementContext on every entitlement refresh — RevenueCat is the source of truth (yearly/quarterly/monthly, null when not subscribed), set alongside is_subscribed. It is not sourced from Bubble/UserContext (that field was never reliably pushed).

The cohort variant is carried by a single People (user-profile) property:

Use payment_variant for all cohort-segmented funnel analysis — break events down by it in reports; it reflects the experience the user actually got. The raw Statsig assignment is not mirrored to Mixpanel as experiment_payments (the payments experiment is suppressed in attachMixpanelMirror, src/utils/experiments.js, to keep one cohort property); use Statsig's own exposure data for randomized (intent-to-treat) experiment analysis.


System

Report Submitted

Fires when a bug report is sent (via clipboard copy or Slack relay).

Property Type Example Required
platform string "ios" yes
has_logs boolean true yes
log_count number 42 yes
delivery string "slack" / "clipboard" yes

Source: logCapture.js

Profile Photo Updated

Fires when user crops and saves a new profile photo.

Property Type Example Required
screen string "profile" yes

Source: MainTabs.jsx

FTUE Walkthrough Completed

Fires when the user finishes all steps of the first-time user experience walkthrough.

Property Type Example Required
steps_seen number 5 yes
is_replay boolean true yes

Source: DrLeoWalkthrough.jsx

TTS Error Occurred

Fires when TTS streaming fails (network error, proxy down, etc.). Centralized in useTTS hook — all TTS consumers get tracking automatically.

Property Type Example Required
backend string "mse" / "pcm" yes
error_message string "Failed to fetch" yes
screen string "insight_playback" / "activity_view" / "simulator_results" yes (via caller context)

Source: useTTS.js

Push Notification Prompt

Push Prompt Shown

Fires when the pre-permission dialog appears.

Property Type Example Required
trigger string "post_signup" / "session_start" / "reinstall" / "act_reminder" yes
mode string "first_time" / "settings_redirect" no (only present for act_reminder trigger)

Source: MainTabs.jsx, useNotificationGate.jsx

Push Prompt Accepted

Fires when user taps "Enable notifications" in the pre-permission dialog. Tracked BEFORE the native OS prompt.

Property Type Example Required
trigger string "post_signup" / "session_start" / "reinstall" / "act_reminder" yes
mode string "first_time" / "settings_redirect" no (only present for act_reminder trigger)

Source: MainTabs.jsx, useNotificationGate.jsx

Push Prompt Dismissed

Fires when user taps "Not now" in the pre-permission dialog.

Property Type Example Required
trigger string "post_signup" / "session_start" / "reinstall" / "act_reminder" yes

Source: MainTabs.jsx, useNotificationGate.jsx

Push Settings Redirect Shown

Fires when the "previously denied" dialog appears in Profile.

Source: MainTabs.jsx

Push Settings Redirect Accepted

Fires when user taps "Open Settings" from the profile notification dialog.

Source: MainTabs.jsx


5. Element Clicked Reference

All Element Clicked events. Properties always include screen, element_type, and element. Extra context properties listed in the last column.

Welcome & Auth

Screen Type Element Extra Source
welcome button lets_go WelcomeScreen
welcome button sign_in WelcomeScreen
signin button back SignInScreen
signin button go_to_signup SignInScreen
signin link continue_with_email SignInScreen
signin link forgot_password SignInScreen
signup button back SignUpScreen
signup button go_to_signin SignUpScreen
signup link continue_with_email SignUpScreen
signup link go_to_signin SignUpScreen

FTUE Walkthrough

Screen Type Element Extra Source
ftue_walkthrough button next step DrLeoWalkthrough
ftue_walkthrough button skip step DrLeoWalkthrough
ftue_walkthrough button back step DrLeoWalkthrough
Screen Type Element Extra Source
main tab journey / simulator / fun / profile MainTabs
{activeTab} button back MainTabs (stack)

Onboarding

Screen Type Element Extra Source
onboarding button back step OnboardingFlow
onboarding button error_go_back OnboardingFlow
onboarding button retry_fetch OnboardingFlow
onboarding_open button mic OpenQuestion
onboarding_open button type OpenQuestion
onboarding_open button skip OpenQuestion
onboarding_open button share_anyway OpenQuestion

Journey

Screen Type Element Extra Source
journey button chapter_menu JourneyPath
journey button chapter_select chapter JourneyPath
journey button node node_id, node_type JourneyPath
journey button start_lesson node_id, node_type JourneyPath
journey button review_step node_id, node_type JourneyPath
journey button repractice_step node_id, node_type JourneyPath
journey button replay_insight node_id, node_type JourneyPath
journey button milestone_review node_id JourneyPath
journey button select_journey HomeSection
journey button send / chat / notifications / previous_journey / next_journey / change_topic / conversation_coach / practical_actions / ask_question HomeSection

Learn Video

Screen Type Element Extra Source
learn_video button play LearnStep
learn_video button pause LearnStep
learn_video button speed speed LearnStep
learn_video button rewind LearnStep
learn_video button mute / unmute LearnStep
learn_video button replay LearnStep
learn_video button skip_to_questions / continue_to_questions LearnStep

Practice

Screen Type Element Extra Source
practice button start_practice chapter PracticeStep

Act

Screen Type Element Extra Source
act button accept chapter ActStep
act button decline chapter ActStep
act button retry chapter ActStep
act_reminder button reminder_tomorrow chapter ReminderSheet
act_reminder button reminder_3_days chapter ReminderSheet
act_reminder button reminder_7_days chapter ReminderSheet
act_reminder button skip_reminder chapter ReminderSheet

Chapter Celebration

Screen Type Element Extra Source
chapter_celebration button continue chapter ChapterCelebration

Step Review

Screen Type Element Extra Source
step_review button rewatch_video StepReview
step_review button close_video StepReview
step_review button play / pause / replay StepReview
step_review button rewind StepReview
step_review button speed speed StepReview
step_review button mute / unmute StepReview

Insight Questions

Screen Type Element Extra Source
insight_questions button back InsightQuestions
insight_questions button close InsightQuestions
insight_questions button mic InsightQuestions
insight_questions button type InsightQuestions
insight_questions button yes / no InsightQuestions
insight_questions button nudge_continue InsightQuestions
insight_questions button nudge_custom InsightQuestions

Insight Other Dialog

Screen Type Element Extra Source
insight_other button mic_start / mic_stop InsightOtherDialog
insight_other button share InsightOtherDialog
insight_other button dialog_closed had_text InsightOtherDialog
insight_other input typing_started InsightOtherDialog
insight_other button open_settings InsightOtherDialog

Insight Playback

Screen Type Element Extra Source
insight_playback button play / pause InsightPlayback
insight_playback button speed speed InsightPlayback
insight_playback button replay InsightPlayback
insight_playback button mute / unmute InsightPlayback
insight_playback button continue InsightPlayback

Fun Zone

Screen Type Element Extra Source
fun banner daily_question FunZoneSection
fun card activity_type type_id FunZoneSection
fun card history_item section: 'activity', item_id FunZoneSection

Activity View

Screen Type Element Extra Source
activity_view button close ActivityView
activity_view button listen ActivityView
activity_view button play / pause ActivityView
activity_view button speed speed ActivityView
activity_view button replay ActivityView
activity_view button retry ActivityView
activity_view button continue ActivityView

Type Detail

Screen Type Element Extra Source
type_detail button create_new section, type_id TypeDetailScreen
type_detail card history_item section, item_id TypeDetailScreen

Simulator Results

Screen Type Element Extra Source
simulator_results button play / pause SimulatorResults
simulator_results button speed speed SimulatorResults
simulator_results button replay SimulatorResults
simulator_results button retry SimulatorResults
simulator_results button done SimulatorResults
simulator_results link read_more / read_less SimulatorResults

Profile & Settings

Screen Type Element Extra Source
profile button upload_photo MainTabs
profile button save_name MainTabs
profile button share_feedback MainTabs
profile button how_bonds_works MainTabs
profile button account_info MainTabs
profile toggle dark_mode preference ThemeContext

Account Info

Screen Type Element Extra Source
account_info button logout MainTabs
account_info button delete_account MainTabs

Name Prompt

Screen Type Element Extra Source
name_prompt button submit_name MainTabs
name_prompt button prefer_not_to_say MainTabs

Partner Name Prompt

Screen Type Element Extra Source
partner_name_prompt button submit_partner_name MainTabs
partner_name_prompt button skip_partner_name MainTabs

Profile Save (Account Info)

Screen Type Element Extra Source
profile button save_partner_name MainTabs (AccountInfoPage)

Daily Question

Screen Type Element Extra Source
daily_question button close DailyQuestion

Share Viewer

Screen Type Element Extra Source
share_viewer button get_bonds ShareCTA

Push Notifications

Event Properties When Source
Push Permission Requested Before native OS prompt is shown notifications.js
Push Permission Responded granted (bool) After user responds to OS prompt or settings redirect notifications.js
Push Player ID Obtained First time player ID is fetched in a session notifications.js

6. Funnels

Onboarding → Insight → Signup Funnel

1. Screen Viewed { screen: 'welcome' }
2. Element Clicked { element: 'lets_go' }
3. Onboarding Intro Viewed              ← one-time only
4. Onboarding Intro Completed           ← if video finished
   OR Onboarding Intro Skipped          ← if CTA tapped before video ends
5. Screen Viewed { screen: 'onboarding' }
6. Onboarding Step Completed  ← repeats per step
7. Onboarding Completed
8. Onboarding Insight Started
9. Onboarding Insight Generated
10. Onboarding Insight Playback Completed / Skipped
11. Onboarding Insight CTA Tapped
12. Screen Viewed { screen: 'signup' }
13. Sign Up Started { method }
14. Sign Up Completed
15. Onboarding Data Connected
16. Screen Viewed { screen: 'ftue_walkthrough' }
17. FTUE Walkthrough Completed

Drop-off: Onboarding Abandoned (back on step 0)
          Onboarding Intro Backed Out (back from intro to welcome)
Resume:   Onboarding Resumed { phase, step, source }
Replay:   Onboarding Intro Replayed (user replays intro video)
Timeout:  Onboarding Insight Timed Out
Back:     Onboarding Step Back { from_step, to_step }
Mic err:  Onboarding Mic Permission Denied / Onboarding Mic Unavailable
No API:   Onboarding Speech API Unavailable
Skip:     Element Clicked { screen: 'ftue_walkthrough', element: 'skip' }

Authentication Funnel

1. Element Clicked { element: 'sign_in' }
2. Screen Viewed { screen: 'signin' }
3. Sign In Started { method }
4. Sign In Completed { method }

Journey Chapter Funnel

Each chapter follows this step sequence:

0. Chapter Started { chapter, chapter_title, coin_cost: 10 }  ← fires on coin-gate confirm

1. Journey Step Started { step_type: 'learn' }
2. Journey Video Watched
3. Journey Step Completed { step_type: 'learn' }

4. Journey Step Started { step_type: 'practice' }
5. Journey Practice Started
6. Simulator Session Started { mode: 'journey' }
7. Simulator Session Completed
8. Journey Practice Completed
9. Journey Step Completed { step_type: 'practice' }

10. Journey Step Started { step_type: 'insight' }
11. Insight Flow Started { type: 'journey' }
12. Insight Question Answered  ← repeats
13. Insight Playback Completed / Skipped
14. Journey Step Completed { step_type: 'insight' }

15. Journey Step Started { step_type: 'act' }
16. Element Clicked { element: 'accept' or 'decline' }
17. Journey Step Completed { step_type: 'act' }

18. Chapter Completed

Drop-off at any stage: Journey Step Abandoned { step_type }

Simulator Funnel (Freeform)

1. Screen Viewed { screen: 'simulator' }
2. Simulator Session Started { mode: 'freeform' }
3. Coins Deducted { amount, context: 'simulator' }  ← fires at stage 2 start
4. Simulator Session Completed { score, skill_level }

Alt exits:
  - Simulator Session Closed (user quits mid-session)
  - Simulator Session Error { code, message }

Loop: Simulator Session Retried → back to step 3

Insight Funnel (Standalone)

1. Insight Flow Started { type: 'learn' or 'activity' }
2. Insight Question Answered  ← repeats
3. Insight Generated
4. Insight Playback Completed / Skipped

Timeout: Insight Generation Timed Out
Drop-off: Insight Flow Closed

Daily Question Funnel

1. Daily Question Viewed { question_id, category }
2. Daily Question Voted { question_id, index }

Partner Connection

1. Partner Connected

Note: Partner invitation is handled in Bubble, not tracked with Element Clicked in the React UI.

Push Notification Permission Funnel

Triggers: post_signup (MainTabs startup), session_start (7-day re-prompt), reinstall (fresh install), act_reminder (journey act reminder gate)

1. Push Prompt Shown
2. Push Prompt Accepted (vs Push Prompt Dismissed = drop-off)
3. Push Permission Requested
4. Push Permission Responded { granted: true }
5. Push Player ID Obtained

Report Event(s) Insight
DAU / WAU / MAU App Opened Daily/weekly/monthly active users
Session Duration App OpenedApp Backgrounded Average time in app per session
Retention Cohort by signup_date, retained via App Opened Day 1/7/30 retention
Onboarding Conversion Onboarding funnel above Step-by-step drop-off rates
Journey Progress Chapter StartedChapter Completed by chapter Chapter start/complete rates
Simulator Engagement Simulator Session StartedCompleted Completion rate, avg score by mode
Feature Adoption % of authenticated users who triggered each feature start Which features resonate
Coin Economy Coins Deducted vs coins earned (Journey, Onboarding) Earn/spend balance
Daily Question Engagement Daily Question ViewedVoted Participation rate
Partner Adoption Partner Connected / total authenticated users Invite conversion

8. Developer Checklist

When adding or changing analytics tracking:

Code patterns

Track a UI interaction:

import { track } from '../utils/analytics';

track('Element Clicked', {
    screen: 'screen_name',
    element_type: 'button',  // button | tab | banner | card | toggle | link
    element: 'element_name',
    // ...extra context
});

Track a domain event:

track('Feature Action', { property: value });
// e.g. track('Partner Connected');

Track a screen view:

import { screen } from '../utils/analytics';

screen('screen_name');