Skip to content

Commit

Permalink
Agrim/CRO-731/ analytics script in deriv app (deriv-com#17180)
Browse files Browse the repository at this point in the history
* fix: script in deriv app

* fix: updates

* fix: update

* fix: types and tracking

* fix: empty commit

* feat: adding loggedIn attribute

* fix: empty commit

* fix: normal event

* fix: add normal event tracking for account signup

* fix: refactor

* fix: updates

* fix: domain update

* fix: pageloadevent

* fix: pageloadevent

* fix: change domain name to check

* fix: testing with consoles

* fix: testing

* fix: tracking

* fix: cache

* fix: cache

* fix: domain

* fix: fixing domain and consoles

* fix: check

* fix: changing domain to binary sx

* fix: changing domain to binary sx

* fix: update analytics version

* fix: add pageview, remove consoles, password screen

* fix: password screen signup no cache

* fix: remove console logs
  • Loading branch information
agrim-deriv authored Nov 1, 2024
1 parent 004d8de commit b159c62
Show file tree
Hide file tree
Showing 19 changed files with 431 additions and 132 deletions.
261 changes: 212 additions & 49 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
},
"dependencies": {
"@babel/preset-typescript": "^7.24.7",
"@deriv-com/analytics": "1.14.0",
"@deriv-com/analytics": "1.25.1",
"@sendbird/chat": "^4.9.7",
"@types/react-transition-group": "^4.4.4",
"babel-jest": "^29.7.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/account/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
},
"dependencies": {
"@binary-com/binary-document-uploader": "^2.4.8",
"@deriv-com/analytics": "1.14.0",
"@deriv-com/analytics": "1.25.1",
"@deriv-com/translations": "1.3.9",
"@deriv-com/utils": "^0.0.36",
"@deriv-com/ui": "1.36.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/api-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"uuid": "^9.0.1"
},
"devDependencies": {
"@deriv-com/analytics": "1.14.0",
"@deriv-com/analytics": "1.25.1",
"@deriv/api-types": "1.0.172",
"@testing-library/react": "^12.0.0",
"@testing-library/react-hooks": "^7.0.2",
Expand Down
2 changes: 1 addition & 1 deletion packages/appstore/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"author": "Deriv",
"license": "Apache-2.0",
"dependencies": {
"@deriv-com/analytics": "1.14.0",
"@deriv-com/analytics": "1.25.1",
"@deriv-com/translations": "1.3.9",
"@deriv-com/ui": "1.36.4",
"@deriv/account": "^1.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/cashier/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"url": "https://github.com/deriv-com/deriv-app/issues"
},
"dependencies": {
"@deriv-com/analytics": "1.14.0",
"@deriv-com/analytics": "1.25.1",
"@deriv-com/ui": "1.36.4",
"@deriv/api": "^1.0.0",
"@deriv/api-types": "1.0.172",
Expand Down
2 changes: 1 addition & 1 deletion packages/cfd/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
},
"dependencies": {
"@deriv-com/ui": "1.36.4",
"@deriv-com/analytics": "1.14.0",
"@deriv-com/analytics": "1.25.1",
"@deriv-com/translations": "1.3.9",
"@deriv-com/utils": "^0.0.36",
"@deriv/account": "^1.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
},
"dependencies": {
"@datadog/browser-rum": "^5.11.0",
"@deriv-com/analytics": "1.14.0",
"@deriv-com/analytics": "1.25.1",
"@deriv-com/quill-tokens": "2.0.4",
"@deriv-com/quill-ui": "1.18.0",
"@deriv-com/translations": "1.3.9",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import QuestionnaireModal from '../QuestionnaireModal';
import ResidenceForm from '../SetResidenceModal/set-residence-form.jsx';
import validateSignupFields from './validate-signup-fields.jsx';
import 'Sass/app/modules/account-signup.scss';
import { trackEventWithCache } from 'Utils/Analytics/analytics.ts';
import cacheTrackEvents from 'Utils/Analytics/analytics.ts';

const AccountSignup = ({
enableApp,
Expand Down Expand Up @@ -56,20 +56,37 @@ const AccountSignup = ({

// didMount lifecycle hook
React.useEffect(() => {
trackEventWithCache({
name: 'ce_virtual_signup_form',
properties: {
action: 'signup_confirmed',
form_name: is_mobile ? 'virtual_signup_web_mobile_default' : 'virtual_signup_web_desktop_default',
// eslint-disable-next-line no-console

cacheTrackEvents.loadEvent([
{
event: {
name: 'ce_virtual_signup_form',
properties: {
action: 'country_selection_screen_opened',
form_name: is_mobile
? 'virtual_signup_web_mobile_default'
: 'virtual_signup_web_desktop_default',
},
},
cache: true,
},
});
trackEventWithCache({
name: 'ce_virtual_signup_form',
properties: {
action: 'country_selection_screen_opened',
form_name: is_mobile ? 'virtual_signup_web_mobile_default' : 'virtual_signup_web_desktop_default',
]);

cacheTrackEvents.loadEvent([
{
event: {
name: 'ce_virtual_signup_form',
properties: {
action: 'signup_confirmed',
form_name: is_mobile
? 'virtual_signup_web_mobile_default'
: 'virtual_signup_web_desktop_default',
},
},
cache: true,
},
});
]);

WS.wait('website_status', 'residence_list').then(() => {
if (clients_country && residence_list) {
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/App/Containers/Layout/app-contents.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useStore, observer } from '@deriv/stores';
import { useGrowthbookGetFeatureValue } from '@deriv/hooks';
import CookieBanner from '../../Components/Elements/CookieBanner/cookie-banner.jsx';
import { useDevice } from '@deriv-com/ui';
// import cacheTrackEvents from 'Utils/Analytics/analytics.ts';

const tracking_status_cookie = new CookieStorage(TRACKING_STATUS_KEY);

Expand Down Expand Up @@ -51,7 +52,10 @@ const AppContents = observer(({ children }) => {
}, []);

React.useEffect(() => {
Analytics.pageView(window.location.href);
Analytics.pageView(window.location.href, {
loggedIn: is_logged_in,
device_type: isMobile ? 'mobile' : 'desktop',
});
// react-hooks/exhaustive-deps
}, [window.location.href]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Button, PasswordInput, PasswordMeter, Text } from '@deriv/components';
import { getErrorMessages, redirectToSignUp } from '@deriv/shared';
import { observer, useStore } from '@deriv/stores';
import { Localize, localize } from '@deriv/translations';
import { trackEventWithCache } from 'Utils/Analytics/analytics.ts';
import cacheTrackEvents from 'Utils/Analytics/analytics.ts';
import SignupSeparatorContainer from '../AccountSignupModal/signup-separator-container.jsx';

import 'Sass/app/modules/account-signup.scss';
Expand All @@ -29,21 +29,20 @@ const PasswordSelectionModal = observer(
const { is_mobile } = ui;

React.useEffect(() => {
trackEventWithCache({
name: 'ce_virtual_signup_form',
properties: {
action: 'password_screen_opened',
form_name: is_mobile ? 'virtual_signup_web_mobile_default' : 'virtual_signup_web_desktop_default',
cacheTrackEvents.loadEvent([
{
event: {
name: 'ce_virtual_signup_form',
properties: {
action: 'password_screen_opened',
form_name: is_mobile
? 'virtual_signup_web_mobile_default'
: 'virtual_signup_web_desktop_default',
},
},
},
});

// Analytics.trackEvent('ce_virtual_signup_form', {
// action: 'password_screen_opened',
// form_name: is_mobile ? 'virtual_signup_web_mobile_default' : 'virtual_signup_web_desktop_default',
// });

//eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
]);
}, [is_mobile]);

return (
<div className='account-signup__password-selection'>
Expand Down
197 changes: 156 additions & 41 deletions packages/core/src/Utils/Analytics/analytics.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,163 @@
interface AnalyticsEvent {
name: string;
properties: {
[key: string]: string;
};
import { Analytics } from '@deriv-com/analytics';
import Cookies from 'js-cookie';

interface Payload {
type: string;
anonymousId: string;
}

const handleCachedEvents = () => {
let eventQueue: AnalyticsEvent[] = [];
const storedEvents = localStorage.getItem('pending_events');
try {
if (storedEvents) {
eventQueue = JSON.parse(storedEvents) as AnalyticsEvent[];
if (eventQueue.length > 0) {
eventQueue.forEach(event => {
window.rudderanalytics.track(event.name, event.properties);
type ResponseData = {
url: string;
method: string;
status: number;
headers: string;
data: string;
payload: Payload;
};
type Event = {
name: string;
properties: Record<string, string>;
cache?: boolean;
};
type Item = {
event: Event;
cache?: boolean;
callback?: (e: Event) => Event;
};
const cacheTrackEvents = {
interval: null as NodeJS.Timeout | null,
responses: [] as ResponseData[],
isTrackingResponses: false,
trackPageUnload: () => {
window.addEventListener('beforeunload', event => {
if (!cacheTrackEvents.isPageViewSent()) {
cacheTrackEvents.push('cached_analytics_page_views', {
name: window.location.href,
properties: {
url: window.location.href,
},
});

eventQueue = [];
localStorage.removeItem('pending_events');
}
});
},
isReady: (): boolean => {
if (typeof Analytics === 'undefined' || Analytics === null) {
return false;
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
};

const setEvent = (event: AnalyticsEvent): void => {
const storedEvents = localStorage.getItem('pending_events');
let eventQueue: AnalyticsEvent[] = [];
if (storedEvents) {
eventQueue = JSON.parse(storedEvents) as AnalyticsEvent[];
}
eventQueue.push(event);
localStorage.setItem('pending_events', JSON.stringify(eventQueue));
};
const instances = Analytics?.getInstances();
return !!instances?.tracking;
},
parseCookies: (cookieName: string): any => {
const cookies: { [key: string]: string } = document.cookie
.split('; ')
.reduce((acc: { [key: string]: string }, cookie: string) => {
const [key, value] = cookie.split('=');
acc[decodeURIComponent(key)] = decodeURIComponent(value);
return acc;
}, {});
try {
return cookies[cookieName] ? JSON.parse(cookies[cookieName]) : null;
} catch (error) {
return null;
}
},
isPageViewSent: (): boolean =>
!!cacheTrackEvents.responses.find(e => e.payload?.type === 'page' && e.payload?.anonymousId),
set: (event: Event) => {
cacheTrackEvents.push('cached_analytics_events', event);
},
push: (cookieName: string, data: Event) => {
let storedCookies: Event[] = [];
const cacheCookie = cacheTrackEvents.parseCookies(cookieName);
if (cacheCookie) storedCookies = cacheCookie;
storedCookies.push(data);
document.cookie = `${cookieName}=${JSON.stringify(storedCookies)}; path=/; Domain=.binary.sx;`;
},
processEvent: (event: Event): Event => {
const clientInfo = Cookies.get('client_information');
if (clientInfo) {
const { email = null } = JSON.parse(clientInfo);
if (email) {
event.properties.email = email;
}
}
if (event?.properties?.email) {
const email = event.properties.email;
delete event.properties.email;
}
return event;
},
track: (originalEvent: Event, cache?: boolean) => {
const event: any = cacheTrackEvents.processEvent(originalEvent);
if (cacheTrackEvents.isReady() && !cache) {
Analytics?.trackEvent(event.name, event.properties);
} else {
cacheTrackEvents.set(event);
}
},
pageView: () => {
if (!cacheTrackEvents.isTrackingResponses) {
cacheTrackEvents.trackPageUnload();
}
let pageViewInterval: NodeJS.Timeout | null = null;
pageViewInterval = setInterval(() => {
const loggedIn = !!Cookies.get('client_information');
const signup_device = Cookies.get('signup_device');

const trackEventWithCache = (event: AnalyticsEvent): void => {
if (window.rudderanalytics) {
handleCachedEvents();
window.rudderanalytics.track(event.name, event.properties);
} else {
setEvent(event);
}
if (Analytics !== undefined && typeof Analytics?.pageView === 'function' && cacheTrackEvents.isReady()) {
Analytics?.pageView(window.location.href, 'Deriv-App', {
loggedIn,
signup_device: signup_device || 'none',
});
}
if (cacheTrackEvents.isPageViewSent()) {
clearInterval(pageViewInterval!);
}
}, 1000);
},
loadEvent: (items: Item[]) => {
items.forEach(({ event, cache }) => {
const { name, properties } = event;
cacheTrackEvents.track(
{
name,
properties,
},
cache
);
});
return cacheTrackEvents;
},
pageLoadEvent: (
items: Array<{ pages?: string[]; excludedPages?: string[]; event: Event; callback?: () => Event }>
) => {
const pathname = window.location.pathname.slice(1);
if (!Array.isArray(items)) {
return cacheTrackEvents;
}
items.forEach(({ pages = [], excludedPages = [], event, callback = null }) => {
let dispatch = false;
if (pages.length) {
if (pages.includes(pathname)) {
dispatch = true;
}
} else if (excludedPages.length) {
if (!excludedPages.includes(pathname)) {
dispatch = true;
}
} else {
dispatch = true;
}
if (dispatch) {
const eventData = callback ? callback() : event;
cacheTrackEvents.loadEvent([
{
event: eventData,
},
]);
}
});
return cacheTrackEvents;
},
};

export { trackEventWithCache, handleCachedEvents };
export default cacheTrackEvents;
1 change: 1 addition & 0 deletions packages/core/src/Utils/Analytics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const AnalyticsInitializer = async () => {
rudderstackKey: process.env.RUDDERSTACK_KEY,
growthbookOptions: {
attributes: {
loggedIn: !!Cookies.get('clients_information'),
account_type: account_type === 'null' ? 'unlogged' : account_type,
app_id: String(getAppId()),
device_type: window.innerWidth <= MAX_MOBILE_WIDTH ? 'mobile' : 'desktop',
Expand Down
Loading

0 comments on commit b159c62

Please sign in to comment.