Onboarding v2 — Mixpanel events
The Mixpanel event tracking spec for the Cur8 onboarding-v2 flow. What we measure, what each event carries, and how to wire it up.
Product calls this flow "Onboarding v1.5"; the code
lives at cur8-mob/src/screens/onboarding-v2/. They are the
same thing.
This document covers Mixpanel events and people-profile
traits only. Customer.io, Avo, Google Ads, session replay and
compliance are out of scope here. The older
ANALYTICS_ARCHITECTURE.md (v3.2) is kept as a reference
for the wider design, including the deferred navigation-listener and
abandonment-tracking work.
onboarding-v2 currently ships with no analytics calls. This document is the spec for what to add, screen by screen.
1What the events answer
| Question | Events |
|---|---|
| Where in onboarding do users drop? | every _pageViewed, each _completed, cur8:onboarding_completed |
| Quiz pass rate | cur8:onboardingQuiz_passed vs _failed |
| Accreditation type mix | cur8:onboardingAccreditation_certificationSelected · certification |
| KYC upload success rate | cur8:onboardingVerification_documentUploaded vs _uploadFailed |
| Attribution source mix | profile attribution_source filtered on cur8:onboarding_completed |
| Personalisation inputs | profile traits set across the flow (see section 5) |
2How events are wired
Every event goes through the shared
@ifgengineering/client-analytics package, the same path
every other cur8-mob event already uses. Screens never call
mixpanel.track directly.
A screen gets a fire function from the useAnalytics hook
and invokes it. The hook returns a promise, so callers
await it. Wrap the call so a failure never blocks the
user, matching existing screens such as home.tsx.
There are two shapes.
Page views
Page views reuse the generic pageView event key. Add the
event-name string to the cur8PageViewEvents union in
packages/client-analytics/src/types.ts, then fire it. The
pageView handler attaches app and
channel for you.
const firePageView = useAnalytics("pageView");
// on screen focus:
(await firePageView)({ eventName: "cur8:onboardingPersonalInfo_pageViewed" });
Action and outcome events
Action and outcome events get their own entry:
-
In
types.ts, add the key to theEventunion and a<Name>Propsinterface. -
In
packages/client-analytics/src/index.ts, add acasethat callstrack("cur8:onboarding…_…", { ...args, app: APP_NAME }). - Fire it from the screen:
const fireCertificationSelected = useAnalytics("onboardingCertificationSelected");
(await fireCertificationSelected)({ certification: "HIGH_NET_WORTH" });
People-profile traits are set inside the same case via
mixpanel.people.set, the way nps_set already
does it. The fire function is the only thing a screen imports.
3Naming
-
Events:
cur8:onboarding<Module>_<action>.cur8:is the team namespace,<Module>is PascalCase,<action>is a past-tense lowerCamelCase verb (_pageViewed,_completed,_passed,_failed,_documentUploaded). -
This matches the existing onboarding events already in Mixpanel
(
cur8:onboardingQuiz_pageViewed,cur8:onboardingBasicInfoPersonal_pageViewed). -
Event properties:
snake_case. Booleans prefixis_/has_. Counts suffix_count. Timestamps suffix_at(ISO 8601). Banded values suffix_band. -
Paginated screens (one route reused per question) keep one event
name and a
question_indexproperty. Do not synthesise a name per question.
Open question — v1 vs v2 names
cur8:onboardingQuiz_pageViewed already exists as a v1
event. This spec assumes v2 replaces v1, so it reuses the clean
names. If v1 and v2 ever run side by side, reusing a name merges the
two in Mixpanel — namespace the v2 events in that case.
4Event taxonomy
Re-derived from the shipped screens. Every screen fires one
_pageViewed on focus. Each module fires one
_completed on its final screen, carrying that module's
captured outputs as properties. No raw PII goes on any event
(age_band, not date of birth).
4.1 Entry & Mandatory Questionnaire
| Event | Properties | Trigger |
|---|---|---|
cur8:onboardingWelcomeBridge_pageViewed |
None | Welcome bridge screen appears. Funnel entry. |
cur8:onboardingMandatoryQuestion_pageViewed |
question_index |
Each of the 3 questionnaire questions appears (paginated route). |
cur8:onboardingEmailPreferences_pageViewed |
None | Email preferences screen appears. |
cur8:onboardingSocialAttribution_pageViewed |
None | Social attribution screen appears. |
cur8:onboardingMandatoryQuestionnaire_completed |
email_preferenceattribution_source |
Social attribution submitted. The questionnaire batch is POSTed at email preferences. Headline funnel anchor. |
email_preference: cur8_capital /
cur8_and_ifg.
attribution_source: google /
instagram / tiktok / youtube /
friend_family / podcast / ifg /
other.
4.2 Basic Info
Seven screens: one explainer, six single-purpose data screens.
| Event | Properties | Trigger |
|---|---|---|
cur8:onboardingBasicInfoExplainer_pageViewed |
None | Explainer appears. |
cur8:onboardingPersonalInfo_pageViewed |
None | Personal info screen appears. |
cur8:onboardingResidentialInfo_pageViewed |
None | Residential info screen appears. |
cur8:onboardingTaxNINumber_pageViewed |
None | NI number screen appears. |
cur8:onboardingTaxResidency_pageViewed |
None | Tax residency screen appears. |
cur8:onboardingTaxSourceOfFunds_pageViewed |
None | Source of funds screen appears. |
cur8:onboardingTaxOccupation_pageViewed |
None | Occupation screen appears. |
cur8:onboardingBasicInfo_completed |
age_band country nationality is_uk_tax_resident source_of_funds_count occupation |
Occupation screen submitted. Headline funnel anchor. |
4.3 Accreditation
Code folder: eligibility/. Four screens.
UNACCREDITED users skip the questionnaire.
| Event | Properties | Trigger |
|---|---|---|
cur8:onboardingAccreditationExplainer_pageViewed |
None | Explainer appears. |
cur8:onboardingCertification_pageViewed |
None | Certification screen appears. |
cur8:onboardingAccreditation_certificationSelected |
certification |
User confirms a certification. Routes to the questionnaire or straight to the declaration. |
cur8:onboardingAccreditationQuestionnaire_pageViewed |
question_index |
Each questionnaire question appears (paginated route). |
cur8:onboardingDeclaration_pageViewed |
None | Declaration screen appears (4 risk-acknowledgement checkboxes). |
cur8:onboardingAccreditation_completed |
certification |
Declaration submitted. Headline funnel anchor. |
certification: SELF_CERTIFIED /
HIGH_NET_WORTH / UNACCREDITED.
4.4 Quiz
FCA appropriateness check. There are no cooldown or "blocked" screens in v2; a failed or rate-limited attempt shows a toast on the same screen.
| Event | Properties | Trigger |
|---|---|---|
cur8:onboardingQuizExplainer_pageViewed |
None | Explainer appears. |
cur8:onboardingQuiz_pageViewed |
question_index |
Each quiz question appears (paginated route). |
cur8:onboardingQuiz_passed |
question_count |
Server returns a passing result. Headline funnel anchor. |
cur8:onboardingQuiz_failed |
blocked_until (ISO or null) |
Server returns failed and/or blockedUntil. blocked_until carries the rate-limit window. |
4.5 Verification (KYC)
Two document types in v2: proof of address and source of funds. No ID-document scan.
| Event | Properties | Trigger |
|---|---|---|
cur8:onboardingVerificationExplainer_pageViewed |
None | Explainer / intro requirements screen appears. |
cur8:onboardingProofOfAddress_pageViewed |
None | Proof of address screen appears. |
cur8:onboardingSourceOfFunds_pageViewed |
None | Source of funds screen appears. |
cur8:onboardingVerificationStatus_pageViewed |
None | Verification status screen appears. |
cur8:onboardingVerification_documentUploaded |
doc_type file_format |
A file upload succeeds. No filename. |
cur8:onboardingVerification_uploadFailed |
doc_type failure_reason |
A file upload errors. |
cur8:onboardingVerification_completed |
document_count |
Verification status submitted (descriptions PUT, KYC marked submitted). Headline funnel anchor. |
doc_type: proof_of_address /
source_of_funds.
file_format: pdf / jpg /
png / heic / other.
4.6 Completion & cross-flow
| Event | Properties | Trigger |
|---|---|---|
cur8:onboardingCompletion_pageViewed |
None | Completion splash appears. |
cur8:onboarding_completed |
None | POST /onboarding/completion succeeds. Terminal funnel event. |
cur8:onboarding_backPressed |
from_screen to_screen |
Back button pressed inside onboarding. |
cur8:onboarding_helpTapped |
screen help_target |
A help / info / support affordance is tapped. |
5People-profile traits
User state lives on the Mixpanel people-profile, not on events. Each
trait is set with mixpanel.people.set inside the event
handler named below, alongside the track call.
| Trait | Set by |
|---|---|
email_preference | cur8:onboardingMandatoryQuestionnaire_completed |
attribution_source | cur8:onboardingMandatoryQuestionnaire_completed |
age_band | cur8:onboardingBasicInfo_completed |
country | cur8:onboardingBasicInfo_completed |
nationality | cur8:onboardingBasicInfo_completed |
is_uk_tax_resident | cur8:onboardingBasicInfo_completed |
occupation | cur8:onboardingBasicInfo_completed |
investor_certification | cur8:onboardingAccreditation_certificationSelected |
quiz_passed_at | cur8:onboardingQuiz_passed |
kyc_status | cur8:onboardingVerification_completed |
onboarding_completed_at | cur8:onboarding_completed |
Identity
onboarding-v2 runs post-signup. The user is already identified at
signup (email-keyed, via safeMixpanelIdentify).
onboarding-v2 fires no identify, alias or
reset calls. Mixpanel's mobile SDK auto-properties
($os, $app_version_string,
$device, etc.) are free; do not duplicate them.
6Headline funnel
| Step | Event |
|---|---|
| 1 | cur8:onboardingWelcomeBridge_pageViewed |
| 2 | cur8:onboardingMandatoryQuestionnaire_completed |
| 3 | cur8:onboardingBasicInfo_completed |
| 4 | cur8:onboardingAccreditation_completed |
| 5 | cur8:onboardingQuiz_passed |
| 6 | cur8:onboardingVerification_completed |
| 7 | cur8:onboarding_completed |
Slice by profile properties country,
attribution_source, investor_certification,
email_preference. Per-screen _pageViewed
events give the within-module drop-off.
7Not covered here
Deliberately cut from the v3.2 architecture doc for this simplified spec:
-
Abandonment events
(
_screenAbandoned,_abandoned,_attemptAbandoned,_docAbandoned) and the navigation-state listener /onboarding_session_idsubsystem they need. Drop-off is read from where users stop in the_pageViewedfunnel. -
active_*_mstiming properties. Mixpanel derives time-between-steps from event timestamps; foreground-pause timing has no precedent in the codebase. -
Per-event metadata (
$insert_id,experiment_variant,flag_resolution) and theexperiment_exposedevent. - Customer.io, Avo, Google Ads, session replay, PII rules and compliance.
See cur8-mob/ANALYTICS_ARCHITECTURE.md for the fuller
v3.2 design if any of the above is revived.