Skip to content

Commit 29f6598

Browse files
authored
chore: add analytics to install modal (#1189)
* chore: adding core analytics structure * added all events and params * tidy * fix lint & test * pr comments * pr fixes
1 parent f4dacaa commit 29f6598

File tree

8 files changed

+89
-7
lines changed

8 files changed

+89
-7
lines changed

packages/sdk-install-modal-web/src/components.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
* It contains typing information for all components that exist in this project.
66
*/
77
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
8+
import { TrackingEvents } from "./components/misc/tracking-events";
9+
export { TrackingEvents } from "./components/misc/tracking-events";
810
export namespace Components {
911
interface MmInstallModal {
1012
/**
@@ -47,6 +49,7 @@ declare global {
4749
interface HTMLMmInstallModalElementEventMap {
4850
"close": any;
4951
"startDesktopOnboarding": any;
52+
"trackAnalytics": { event: TrackingEvents, params?: Record<string, unknown> };
5053
}
5154
interface HTMLMmInstallModalElement extends Components.MmInstallModal, HTMLStencilElement {
5255
addEventListener<K extends keyof HTMLMmInstallModalElementEventMap>(type: K, listener: (this: HTMLMmInstallModalElement, ev: MmInstallModalCustomEvent<HTMLMmInstallModalElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
@@ -113,6 +116,7 @@ declare namespace LocalJSX {
113116
"link"?: string;
114117
"onClose"?: (event: MmInstallModalCustomEvent<any>) => void;
115118
"onStartDesktopOnboarding"?: (event: MmInstallModalCustomEvent<any>) => void;
119+
"onTrackAnalytics"?: (event: MmInstallModalCustomEvent<{ event: TrackingEvents, params?: Record<string, unknown> }>) => void;
116120
"preferDesktop"?: boolean;
117121
"sdkVersion"?: string;
118122
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export enum TrackingEvents {
2+
SDK_MODAL_VIEWED = 'sdk_modal_viewed',
3+
SDK_MODAL_BUTTON_CLICKED = 'sdk_modal_button_clicked',
4+
SDK_MODAL_TOGGLE_CHANGED = 'sdk_modal_toggle_changed',
5+
}

packages/sdk-install-modal-web/src/components/mm-install-modal/mm-install-modal.tsx

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import CloseButton from '../misc/CloseButton';
1010
import Logo from '../misc/Logo';
1111
import encodeQR from '@paulmillr/qr';
1212
import { SimpleI18n } from '../misc/simple-i18n';
13+
import { TrackingEvents } from '../misc/tracking-events';
14+
1315
@Component({
1416
tag: 'mm-install-modal',
1517
styleUrl: '../style.css',
@@ -31,6 +33,8 @@ export class InstallModal {
3133

3234
@Event() startDesktopOnboarding: EventEmitter;
3335

36+
@Event() trackAnalytics: EventEmitter<{ event: TrackingEvents, params?: Record<string, unknown> }>;
37+
3438
@State() tab: number = 1;
3539

3640
@State() isDefaultTab: boolean = true;
@@ -49,6 +53,16 @@ export class InstallModal {
4953
this.i18nInstance = new SimpleI18n();
5054
}
5155

56+
componentDidLoad() {
57+
this.trackAnalytics.emit({
58+
event: TrackingEvents.SDK_MODAL_VIEWED,
59+
params: {
60+
extensionInstalled: false,
61+
tab: this.tab === 1 ? 'desktop' : 'mobile',
62+
},
63+
});
64+
}
65+
5266
async connectedCallback() {
5367
await this.i18nInstance.init({
5468
fallbackLng: 'en'
@@ -70,11 +84,27 @@ export class InstallModal {
7084
}
7185

7286
onStartDesktopOnboardingHandler() {
87+
this.trackAnalytics.emit({
88+
event: TrackingEvents.SDK_MODAL_BUTTON_CLICKED,
89+
params: {
90+
button_type: 'install_extension',
91+
tab: 'desktop',
92+
},
93+
});
7394
this.startDesktopOnboarding.emit();
7495
}
7596

76-
setTab(newTab: number) {
77-
this.tab = newTab
97+
setTab(newTab: number, isUserAction: boolean = false) {
98+
if (isUserAction) {
99+
this.trackAnalytics.emit({
100+
event: TrackingEvents.SDK_MODAL_TOGGLE_CHANGED,
101+
params: {
102+
toggle: this.tab === 1 ? 'desktop_to_mobile' : 'mobile_to_desktop',
103+
},
104+
});
105+
}
106+
107+
this.tab = newTab;
78108
this.isDefaultTab = false;
79109
}
80110

@@ -84,8 +114,7 @@ export class InstallModal {
84114
}
85115

86116
const t = (key: string) => this.i18nInstance.t(key);
87-
88-
const currentTab = this.isDefaultTab ? this.preferDesktop ? 1 : 2 : this.tab
117+
const currentTab = this.isDefaultTab ? this.preferDesktop ? 1 : 2 : this.tab;
89118

90119
const svgElement = encodeQR(this.link, "svg", {
91120
ecc: "medium",
@@ -110,13 +139,13 @@ export class InstallModal {
110139
<div class='tabcontainer'>
111140
<div class='flexContainer'>
112141
<div
113-
onClick={() => this.setTab(1)}
142+
onClick={() => this.setTab(1, true)}
114143
class={`tab flexItem ${currentTab === 1 ? 'tabactive': ''}`}
115144
>
116145
{t('DESKTOP')}
117146
</div>
118147
<div
119-
onClick={() => this.setTab(2)}
148+
onClick={() => this.setTab(2, true)}
120149
class={`tab flexItem ${currentTab === 2 ? 'tabactive': ''}`}
121150
>
122151
{t('MOBILE')}

packages/sdk/src/services/RemoteConnection/ModalManager/showInstallModal.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ describe('showInstallModal', () => {
5252
terminate: expect.any(Function),
5353
debug: state.developerMode,
5454
connectWithExtension: expect.any(Function),
55+
onAnalyticsEvent: expect.any(Function),
5556
});
5657
expect(mockModalsInstall).toHaveBeenCalledTimes(1);
5758
expect(mockInstallModalMount).toHaveBeenCalledWith(link);

packages/sdk/src/services/RemoteConnection/ModalManager/showInstallModal.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { TrackingEvents } from '@metamask/sdk-communication-layer';
12
import { logger } from '../../../utils/logger';
23
import {
34
RemoteConnectionProps,
@@ -34,6 +35,22 @@ export function showInstallModal(
3435
options.connectWithExtensionProvider?.();
3536
return false;
3637
},
38+
onAnalyticsEvent: ({
39+
event,
40+
params,
41+
}: {
42+
event: TrackingEvents;
43+
params?: Record<string, any>;
44+
}) => {
45+
const extended = {
46+
...params,
47+
sdkVersion: options.sdk.getVersion(),
48+
dappId: options.dappMetadata?.name,
49+
source: options._source,
50+
url: options.dappMetadata?.url,
51+
};
52+
state.analytics?.send({ event, params: extended });
53+
},
3754
});
3855
state.installModal?.mount?.(link);
3956
}

packages/sdk/src/services/RemoteConnection/RemoteConnection.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
KeyInfo,
99
RemoteCommunication,
1010
StorageManagerProps,
11+
TrackingEvents,
1112
} from '@metamask/sdk-communication-layer';
1213
import { MetaMaskInstaller } from '../../Platform/MetaMaskInstaller';
1314
import { PlatformManager } from '../../Platform/PlatfformManager';
@@ -55,13 +56,20 @@ export interface RemoteConnectionProps {
5556
*/
5657
modals: {
5758
onPendingModalDisconnect?: () => void;
58-
install?: (params: {
59+
install?: (args: {
5960
link: string;
6061
debug?: boolean;
6162
preferDesktop?: boolean;
6263
installer: MetaMaskInstaller;
6364
terminate?: () => void;
6465
connectWithExtension?: () => void;
66+
onAnalyticsEvent: ({
67+
event,
68+
params,
69+
}: {
70+
event: TrackingEvents;
71+
params?: Record<string, unknown>;
72+
}) => void;
6573
}) => {
6674
unmount?: (shouldTerminate?: boolean) => void;
6775
mount?: (link: string) => void;

packages/sdk/src/ui/InstallModal/InstallModal-web.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { TrackingEvents } from '@metamask/sdk-communication-layer';
12
import packageJson from '../../../package.json';
23
import { MetaMaskInstaller } from '../../Platform/MetaMaskInstaller';
34
import { logger } from '../../utils/logger';
@@ -10,13 +11,21 @@ const sdkWebInstallModal = ({
1011
terminate,
1112
connectWithExtension,
1213
preferDesktop,
14+
onAnalyticsEvent,
1315
}: {
1416
link: string;
1517
debug?: boolean;
1618
preferDesktop?: boolean;
1719
installer: MetaMaskInstaller;
1820
terminate?: () => void;
1921
connectWithExtension?: () => void;
22+
onAnalyticsEvent: ({
23+
event,
24+
params,
25+
}: {
26+
event: TrackingEvents;
27+
params?: Record<string, unknown>;
28+
}) => void;
2029
}) => {
2130
let modalLoader: ModalLoader | null = null;
2231
let div: HTMLDivElement | null = null;
@@ -94,6 +103,7 @@ const sdkWebInstallModal = ({
94103
link,
95104
metaMaskInstaller: installer,
96105
onClose: unmount,
106+
onAnalyticsEvent,
97107
})
98108
.catch((err) => {
99109
console.error(`[UI: InstallModal-web: sdkWebInstallModal()]`, err);

packages/sdk/src/ui/InstallModal/Modal-web.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { TrackingEvents } from '@metamask/sdk-communication-layer';
12
import type { Components } from '@metamask/sdk-install-modal-web';
23

34
export interface InstallWidgetProps extends Components.MmInstallModal {
@@ -6,6 +7,10 @@ export interface InstallWidgetProps extends Components.MmInstallModal {
67
metaMaskInstaller: {
78
startDesktopOnboarding: () => void;
89
};
10+
onAnalyticsEvent: (event: {
11+
event: TrackingEvents;
12+
params?: Record<string, unknown>;
13+
}) => void;
914
}
1015

1116
export interface PendingWidgetProps extends Components.MmPendingModal {
@@ -80,6 +85,9 @@ export default class ModalLoader {
8085
'startDesktopOnboarding',
8186
props.metaMaskInstaller.startDesktopOnboarding,
8287
);
88+
89+
modal.addEventListener('trackAnalytics', ((e: CustomEvent) =>
90+
props.onAnalyticsEvent?.(e.detail)) as EventListener);
8391
props.parentElement.appendChild(modal);
8492
}
8593

0 commit comments

Comments
 (0)