The Mixpanel event tracking spec for the auth-v2 flow: the landing
carousel, sign-up, login, email verification, two-factor and password
reset. The code lives at cur8-mob/src/screens/auth-v2/.
This doc covers Mixpanel events, the identity model and
people-profile traits. The companion
onboarding-v2/ANALYTICS.md covers the flow that runs
straight after auth.
Note: auth-v2 reuses the existing auth events in
@ifgengineering/client-analytics. An earlier draft of this
spec invented a new auth_v2_* event prefix; that prefix is
dropped. The events below are the established all:* auth
events, which are already wired and already handle identity, plus a
short list of new events for signals the legacy set never had.
1. What the events answer
| Question | Events |
|---|---|
| Sign-up conversion | all:signup_attempted to
all:signup_success |
| Login success rate | all:login_attempted vs all:login_success /
all:login_failed |
| Two-factor drop-off | all:2fa_required to all:2fa_success |
| Where sign-up or login fails | all:signup_failed.reason,
all:login_failed.reason |
| Password reset completion | all:forgotPassword_clicked to
all:forgotPasswordSetPassword_clicked |
| Auth method mix | method property (email /
apple / google / biometrics) |
2. The flow
auth-v2 has eight registered routes
(cur8-mob/src/navigation/authV2.tsx,
AuthV2StackParamList). Landing is the entry
point.
- Landing carousel, with Get started and Log in CTAs plus Apple / Google buttons.
- Sign up:
CreateAccount(email then password) toVerifyEmail(OTP) to the onboarding-v2 handoff. - Login:
Login(email and password) toBiometricsModal(if Face ID or Touch ID is enrolled) toTwoFactorVerification(if 2FA is on) to the onboarding-v2 handoff. - Password reset:
LogintoForgotPassword(enter email) toResetPassword(new password, plus OTP when 2FA is on).
Auth ends by handing off to onboarding-v2, which begins at
cur8:onboardingWelcomeBridge_pageViewed.
3. How events are wired
Events go through the shared
@ifgengineering/client-analytics package. A screen hook
gets a fire function from useAnalytics(eventKey), which
returns a promise, and invokes it with the event's properties:
const fireSignup = useAnalytics("signupAttempt");
(await fireSignup)({ email, method: "email" });
The eight reused events in section 5.1 already have
handlers in the client-analytics switch, already
emit to Mixpanel and Customer.io, and signupAttempt /
login already perform the identity calls (section 6).
Wiring auth-v2 to them is a matter of calling the right keys.
The current auth-v2 code routes through
useAuthV2Analytics
(auth-v2/components/shared/useAuthV2Analytics.ts), a hook
that fires 16 auth_v2_* names. Those names have no handler
in the switch, so they fall through to the default: no-op
and never reach Mixpanel. useAuthV2Analytics should be
reworked to fire the real event keys below, or removed in favour of
calling useAnalytics directly.
The six new events in section 5.2 need a case adding to
the switch in packages/client-analytics/src/index.ts, and
their keys adding to the Event union in
types.ts.
4. Naming
auth-v2 events live in the established all: auth
namespace, the same one the legacy auth events already use
(all:signup_attempted). There is no auth_v2_
prefix. New events follow the same
all:<area>_<verb> shape.
Note: the legacy event keys carry a
spelling slip: forogtPasswordClick and friends (forgot
misspelled). The keys are what useAnalytics is called with,
so the typo must be matched exactly. The emitted Mixpanel names are
spelled correctly (all:forgotPassword_clicked). Fixing the
key spelling is a separate cleanup, noted in section 8.
Event properties stay minimal and privacy-safe: no passwords, OTP codes, or unnecessary raw email values beyond what the identity calls already require.
5. Event taxonomy
5.1 Reused events
These already exist in client-analytics. auth-v2 fires
them as-is.
| Mixpanel event | Event key | Auth-v2 trigger | Properties |
|---|---|---|---|
all:signup_attempted |
signupAttempt |
Create Account form submitted | email, method, attribution,
utm |
all:signup_success |
signupSuccess |
Verify Email OTP accepted, sign-up complete | email |
all:login_attempted |
login |
Login form submitted | email, method |
all:2fa_attempted |
twoFaAttempted |
2FA code entered | channel, method |
all:2fa_success |
twoFaSuccess |
2FA code verified | channel, method |
all:forgotPassword_clicked |
forogtPasswordClick |
"Forgot password?" tapped on Login | none |
all:forgotPasswordSubmitEmail_clicked |
forogtPasswordSubmitEmailClick |
Email submitted on Forgot Password | email |
all:forgotPasswordSetPassword_clicked |
forogtPasswordSetPasswordClick |
New password set on Reset Password | none |
Note: signupAttempt already filters out
@test.com and @delete.com addresses and fires
a Google Ads sign-up conversion. auth-v2 inherits both by reusing
it.
5.2 New events
auth-v2 surfaces signals the legacy set never had: failures, the
login-success terminal, and the 2FA-required branch. These need adding
to client-analytics, in the same all:
namespace.
| Mixpanel event | Auth-v2 trigger | Properties |
|---|---|---|
all:signup_failed |
Create Account errors | method, reason |
all:login_success |
Login authenticated | email, method |
all:login_failed |
Login errors | method, reason |
all:2fa_required |
Password auth succeeds but the account has 2FA on | channel, method |
all:2fa_failed |
2FA code rejected | channel, method, reason |
all:emailVerification_failed |
Verify Email OTP rejected or errors | reason |
method: email / apple /
google / biometrics. reason: a
short failure code such as api_error, never a raw exception
string.
6. Identity model
auth-v2 is where an anonymous device becomes an identified user. The reused events handle this already, so there is no separate work to do:
signupAttemptcallsmixpanel.alias(email)thenmixpanel.identify(email), sets the people-profile traits below withset_once, and calls Customer.ioidentify.logincallsmixpanel.identify(email), updatesLatestLoginDate, and appends tolist_logins.
The identity key is the email address.
investorId would be a more durable join key, but email is
the established convention across the codebase and the onboarding-v2
doc, so auth-v2 keeps it.
People-profile traits set during auth (legacy trait names, kept as-is):
| Trait | Set by |
|---|---|
$email |
signupAttempt (set_once) |
Sign Up Date |
signupAttempt (set_once) |
Account Type |
signupAttempt (set_once) |
LatestLoginDate |
login |
list_logins |
login (appended) |
Logout should call mixpanel.reset(). That is handled in
session / Redux teardown, not in auth-v2; confirm it fires.
7. Auth funnel
Sign-up funnel
| Step | Event |
|---|---|
| 1 | all:signup_attempted |
| 2 | all:signup_success |
| 3 | cur8:onboardingWelcomeBridge_pageViewed (onboarding-v2
handoff) |
Login funnel
| Step | Event |
|---|---|
| 1 | all:login_attempted |
| 2 | all:login_success |
| 3 | cur8:onboardingWelcomeBridge_pageViewed (onboarding-v2
handoff) |
Slice both by method. When 2FA is on,
all:2fa_required to all:2fa_success sits
between login and the onboarding handoff. signupAttempt
does the heavy lifting (identity, conversion), so it anchors the sign-up
funnel even though its name says "attempted".
8. Gaps and open questions
- The new events (section 5.2) need wiring. Six
caseblocks in theclient-analyticsswitch, plusEvent-union entries. Until then, failures and the 2FA-required branch are unmeasured. useAuthV2Analyticsfires dead names. The hook's 16auth_v2_*events hit thedefault:no-op. Rework the hook to fire the keys in section 5, or drop it.- Legacy key spelling.
forogtPasswordClick,forogtPasswordSubmitEmailClickandforogtPasswordSetPasswordClickare misspelled. Renaming the keys is a clean-up that touches every call site; the Mixpanel names are already correct so analytics is unaffected either way. - Screen-level granularity. The legacy auth events
track actions, not screen views. There is no per-screen
_viewedevent, so within-screen drop-off (for example, landing on Login but never submitting) is not visible. Add screen-view events later if that funnel detail is needed. signupAttemptnaming. It fires on form submit but performs the full identity and a Google Ads conversion, so it behaves as the real sign-up event. The name is legacy and kept for reuse.- Namespace split. auth-v2 uses
all:, onboarding-v2 usescur8:onboarding<Screen>_<action>. Two conventions across one user journey. Worth a deliberate decision, but reusingall:for auth is the lower-risk path because those events already exist and work.