chore(analytics): Improve tracking of login and onboarding completion events (#21760)

Improves tracking of login and successful onboarding completion according to
requests from non-technical analytics users and to synchronize with desktop. We
now publish two new events user-logged-in and onboarding-completed.

Fixes https://github.com/status-im/status-mobile/issues/21679

Areas that may be impacted: no impact is expected whatsoever, but login and
onboarding code were lightly touched.

- Event user-logged-in is always published, whenever the profile login is
  successful. If the user created a profile, we publish both
  onboarding-completed and user-logged-in.
- Event onboarding-completed is published if the user created a profile,
  recovered using seed phrase or paired devices successfully.
This commit is contained in:
Icaro Motta 2024-12-05 18:40:10 -03:00 committed by GitHub
parent 2343d9be1e
commit 1391c48e39
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 97 additions and 89 deletions

View File

@ -4,7 +4,6 @@
[re-frame.interceptor :as interceptor] [re-frame.interceptor :as interceptor]
status-im.contexts.centralized-metrics.effects status-im.contexts.centralized-metrics.effects
[status-im.contexts.centralized-metrics.tracking :as tracking] [status-im.contexts.centralized-metrics.tracking :as tracking]
[taoensso.timbre :as log]
[utils.re-frame :as rf])) [utils.re-frame :as rf]))
(defn push-event? (defn push-event?
@ -16,7 +15,6 @@
[context] [context]
(when (push-event? (interceptor/get-coeffect context :db)) (when (push-event? (interceptor/get-coeffect context :db))
(when-let [event (tracking/metrics-event (interceptor/get-coeffect context :event))] (when-let [event (tracking/metrics-event (interceptor/get-coeffect context :event))]
(log/debug "tracking event" event)
(if (or (seq? event) (vector? event)) (if (or (seq? event) (vector? event))
(doseq [e event] (doseq [e event]
(native-module/add-centralized-metric e)) (native-module/add-centralized-metric e))

View File

@ -6,12 +6,15 @@
[status-im.navigation.screens :as screens])) [status-im.navigation.screens :as screens]))
(defn key-value-event (defn key-value-event
[event-name event-value] ([event-name]
{:metric (key-value-event event-name nil))
{:eventName event-name ([event-name event-value]
:platform platform/os (cond-> {:metric
:appVersion build/app-short-version {:eventName event-name
:eventValue event-value}}) :platform platform/os
:appVersion build/app-short-version}}
event-value
(assoc-in [:metric :eventValue] event-value))))
(defn user-journey-event (defn user-journey-event
[action] [action]
@ -41,11 +44,16 @@
(defn track-view-id-event (defn track-view-id-event
[view-id] [view-id]
(if-let [screen (get screens/screens-by-name view-id)] (let [screen (get screens/screens-by-name view-id)]
(when (get-in screen [:metrics :track?]) (cond-> []
(screen-event screen {})) (get-in screen [:metrics :track?])
(when (contains? view-ids-to-track view-id) (conj (screen-event screen {}))
(navigation-event (name view-id)))))
(contains? view-ids-to-track view-id)
(conj (navigation-event (name view-id)))
(= :screen/onboarding.syncing-results view-id)
(conj (key-value-event "onboarding-completed")))))
(defn navigated-to-collectibles-tab-event (defn navigated-to-collectibles-tab-event
[location] [location]
@ -60,6 +68,13 @@
:centralized-metrics/toggle-centralized-metrics :centralized-metrics/toggle-centralized-metrics
(key-value-event "events.metrics-enabled" {:enabled rf-event-parameter}) (key-value-event "events.metrics-enabled" {:enabled rf-event-parameter})
:profile.login/non-critical-initialization
(key-value-event "user-logged-in")
(:profile.create/create-and-login
:profile.recover/recover-and-login)
(key-value-event "onboarding-completed")
:set-view-id :set-view-id
(track-view-id-event rf-event-parameter) (track-view-id-event rf-event-parameter)

View File

@ -42,19 +42,19 @@
(deftest track-view-id-event-test (deftest track-view-id-event-test
(testing "returns correct navigation event for view-id" (testing "returns correct navigation event for view-id"
(is (= {:metric (is (= [{:metric
{:eventName "navigation" {:eventName "navigation"
:platform platform-os :platform platform-os
:appVersion app-version :appVersion app-version
:eventValue {:viewId "communities-stack"}}} :eventValue {:viewId "communities-stack"}}}]
(tracking/track-view-id-event :communities-stack))) (tracking/track-view-id-event :communities-stack)))
(is (= {:metric (is (= [{:metric
{:eventName "navigation" {:eventName "navigation"
:platform platform-os :platform platform-os
:appVersion app-version :appVersion app-version
:eventValue {:viewId "onboarding.create-profile-info"}}} :eventValue {:viewId "onboarding.create-profile-info"}}}]
(tracking/track-view-id-event :screen/onboarding.create-profile))) (tracking/track-view-id-event :screen/onboarding.create-profile)))
(is (nil? (tracking/track-view-id-event :unknown-stack))))) (is (= [] (tracking/track-view-id-event :unknown-stack)))))
(deftest tracked-event-test (deftest tracked-event-test
(testing "returns correct event for given inputs" (testing "returns correct event for given inputs"
@ -70,16 +70,16 @@
:appVersion app-version :appVersion app-version
:eventValue {:enabled true}}} :eventValue {:enabled true}}}
(tracking/metrics-event [:centralized-metrics/toggle-centralized-metrics true]))) (tracking/metrics-event [:centralized-metrics/toggle-centralized-metrics true])))
(is (= {:metric (is (= [{:metric
{:eventName "navigation" {:eventName "navigation"
:platform platform-os :platform platform-os
:appVersion app-version :appVersion app-version
:eventValue {:viewId "wallet-stack"}}} :eventValue {:viewId "wallet-stack"}}}]
(tracking/metrics-event [:set-view-id :wallet-stack]))) (tracking/metrics-event [:set-view-id :wallet-stack])))
(is (nil? (tracking/metrics-event [:unknown-event]))) (is (nil? (tracking/metrics-event [:unknown-event])))
(is (= {:metric (is (= [{:metric
{:eventName "navigation" {:eventName "navigation"
:platform platform-os :platform platform-os
:appVersion app-version :appVersion app-version
:eventValue {:viewId "onboarding.intro"}}} :eventValue {:viewId "onboarding.intro"}}}]
(tracking/metrics-event [:set-view-id :screen/onboarding.intro]))))) (tracking/metrics-event [:set-view-id :screen/onboarding.intro])))))

View File

@ -3,8 +3,6 @@
[re-frame.core :as re-frame] [re-frame.core :as re-frame]
status-im.common.biometric.events status-im.common.biometric.events
[status-im.constants :as constants] [status-im.constants :as constants]
[status-im.contexts.profile.create.events :as profile.create]
[status-im.contexts.profile.recover.events :as profile.recover]
[status-im.contexts.shell.constants :as shell.constants] [status-im.contexts.shell.constants :as shell.constants]
[taoensso.timbre :as log] [taoensso.timbre :as log]
[utils.i18n :as i18n] [utils.i18n :as i18n]
@ -78,30 +76,28 @@
(fn [_ [error]] (fn [_ [error]]
{:dispatch [:biometric/show-message (ex-cause error)]})) {:dispatch [:biometric/show-message (ex-cause error)]}))
(rf/defn create-account-and-login (rf/reg-event-fx :onboarding/create-account-and-login
{:events [:onboarding/create-account-and-login]} (fn [{:keys [db]}]
[{:keys [db] :as cofx}] (let [{:keys [seed-phrase]
(let [{:keys [seed-phrase] :as profile} (:onboarding/profile db)
:as profile} (:onboarding/profile db) syncing-account-recovered? (and (seq (:syncing/key-uid db))
syncing-account-recovered? (and (seq (:syncing/key-uid db)) (= (:syncing/key-uid db)
(= (:syncing/key-uid db) (get-in db [:onboarding/profile :key-uid])))]
(get-in db [:onboarding/profile :key-uid])))] {:db (-> db
(rf/merge cofx (dissoc :profile/login)
{:fx [[:dispatch (dissoc :auth-method)
[:navigate-to-within-stack (assoc :onboarding/new-account? true))
[:screen/onboarding.preparing-status :fx [[:dispatch
(get db [:navigate-to-within-stack
:onboarding/navigated-to-enter-seed-phrase-from-screen [:screen/onboarding.preparing-status
:screen/onboarding.new-to-status)]]] (get db
(when-not syncing-account-recovered? :onboarding/navigated-to-enter-seed-phrase-from-screen
[:dispatch [:syncing/clear-syncing-installation-id]])] :screen/onboarding.new-to-status)]]]
:db (-> db (when-not syncing-account-recovered?
(dissoc :profile/login) [:dispatch [:syncing/clear-syncing-installation-id]])
(dissoc :auth-method) (if seed-phrase
(assoc :onboarding/new-account? true))} [:dispatch [:profile.recover/recover-and-login profile]]
(if seed-phrase [:dispatch [:profile.create/create-and-login profile]])]})))
(profile.recover/recover-profile-and-login profile)
(profile.create/create-profile-and-login profile)))))
(rf/defn on-delete-profile-success (rf/defn on-delete-profile-success
{:events [:onboarding/on-delete-profile-success]} {:events [:onboarding/on-delete-profile-success]}
@ -207,4 +203,3 @@
:on-error #(log/error "failed to save biometrics" :on-error #(log/error "failed to save biometrics"
{:key-uid key-uid {:key-uid key-uid
:error %})})))) :error %})}))))

View File

@ -6,14 +6,13 @@
[utils.re-frame :as rf] [utils.re-frame :as rf]
[utils.security.core :as security])) [utils.security.core :as security]))
(rf/defn create-profile-and-login (rf/reg-event-fx :profile.create/create-and-login
{:events [:profile.create/create-and-login]} (fn [{:keys [db]} [{:keys [display-name password image-path color]}]]
[{:keys [db]} {:keys [display-name password image-path color]}] (let [login-sha3-password (native-module/sha3 (security/safe-unmask-data password))]
(let [login-sha3-password (native-module/sha3 (security/safe-unmask-data password))] {:db (assoc-in db [:syncing :login-sha3-password] login-sha3-password)
{:db (assoc-in db [:syncing :login-sha3-password] login-sha3-password) :fx [[:effects.profile/create-and-login
:effects.profile/create-and-login (assoc (profile.config/create)
(assoc (profile.config/create) :displayName display-name
:displayName display-name :password login-sha3-password
:password login-sha3-password :imagePath (profile.config/strip-file-prefix image-path)
:imagePath (profile.config/strip-file-prefix image-path) :customizationColor color)]]})))
:customizationColor color)}))

View File

@ -7,23 +7,22 @@
[utils.re-frame :as rf] [utils.re-frame :as rf]
[utils.security.core :as security])) [utils.security.core :as security]))
(rf/defn recover-profile-and-login (rf/reg-event-fx :profile.recover/recover-and-login
{:events [:profile.recover/recover-and-login]} (fn [{:keys [db]} [{:keys [display-name password image-path color seed-phrase]}]]
[{:keys [db]} {:keys [display-name password image-path color seed-phrase]}] (let [login-sha3-password (native-module/sha3 (security/safe-unmask-data password))]
(let [login-sha3-password (native-module/sha3 (security/safe-unmask-data password))] {:db
{:db (-> db
(-> db (assoc :onboarding/recovered-account? true)
(assoc :onboarding/recovered-account? true) (assoc-in [:syncing :login-sha3-password] login-sha3-password))
(assoc-in [:syncing :login-sha3-password] login-sha3-password)) :fx
[[:effects.profile/restore-and-login
:effects.profile/restore-and-login (assoc (profile.config/create)
(assoc (profile.config/create) :displayName display-name
:displayName display-name :mnemonic (security/safe-unmask-data seed-phrase)
:mnemonic (security/safe-unmask-data seed-phrase) :password login-sha3-password
:password login-sha3-password :imagePath (profile.config/strip-file-prefix image-path)
:imagePath (profile.config/strip-file-prefix image-path) :customizationColor (or color constants/profile-default-color)
:customizationColor (or color constants/profile-default-color) :fetchBackup true)]]})))
:fetchBackup true)}))
(rf/reg-event-fx :profile.recover/validate-recovery-phrase (rf/reg-event-fx :profile.recover/validate-recovery-phrase
(fn [_ [phrase {:keys [on-success on-error]}]] (fn [_ [phrase {:keys [on-success on-error]}]]

View File

@ -31,7 +31,9 @@
status-im.contexts.network.events status-im.contexts.network.events
status-im.contexts.onboarding.common.overlay.events status-im.contexts.onboarding.common.overlay.events
status-im.contexts.onboarding.events status-im.contexts.onboarding.events
status-im.contexts.profile.create.events
status-im.contexts.profile.events status-im.contexts.profile.events
status-im.contexts.profile.recover.events
status-im.contexts.profile.settings.events status-im.contexts.profile.settings.events
status-im.contexts.settings.language-and-currency.events status-im.contexts.settings.language-and-currency.events
status-im.contexts.settings.wallet.saved-addresses.events status-im.contexts.settings.wallet.saved-addresses.events