-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathgoogle-analytics.js
118 lines (108 loc) · 4 KB
/
google-analytics.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
const GA_ENDPOINT = 'https://www.google-analytics.com/mp/collect';
const GA_DEBUG_ENDPOINT = 'https://www.google-analytics.com/debug/mp/collect';
const MEASUREMENT_ID = 'G-ZJZ7R8RXRQ';
const API_SECRET = 'Z1OzBT7jSLSp0p42ufgSQw';
const DEFAULT_ENGAGEMENT_TIME_MSEC = 100;
// Duration of inactivity after which a new session is created
const SESSION_EXPIRATION_IN_MIN = 30;
export class Analytics {
constructor(debug = false) {
this.debug = debug;
}
// Returns the client id, or creates a new one if one doesn't exist.
// Stores client id in local storage to keep the same client id as long as
// the extension is installed.
async getOrCreateClientId() {
let { clientId } = await chrome.storage.local.get('clientId');
if (!clientId) {
// Generate a unique client ID, the actual value is not relevant
clientId = self.crypto.randomUUID();
await chrome.storage.local.set({ clientId });
}
return clientId;
}
// Returns the current session id, or creates a new one if one doesn't exist or
// the previous one has expired.
async getOrCreateSessionId() {
// Use storage.session because it is only in memory
let { sessionData } = await chrome.storage.session.get('sessionData');
const currentTimeInMs = Date.now();
// Check if session exists and is still valid
if (sessionData && sessionData.timestamp) {
// Calculate how long ago the session was last updated
const durationInMin = (currentTimeInMs - sessionData.timestamp) / 60000;
// Check if last update lays past the session expiration threshold
if (durationInMin > SESSION_EXPIRATION_IN_MIN) {
// Clear old session id to start a new session
sessionData = null;
} else {
// Update timestamp to keep session alive
sessionData.timestamp = currentTimeInMs;
await chrome.storage.session.set({ sessionData });
}
}
if (!sessionData) {
// Create and store a new session
sessionData = {
session_id: currentTimeInMs.toString(),
timestamp: currentTimeInMs.toString()
};
await chrome.storage.session.set({ sessionData });
}
return sessionData.session_id;
}
// Fires an event with optional params. Event names must only include letters and underscores.
async fireEvent(name, params = {}) {
// Configure session id and engagement time if not present, for more details see:
// https://developers.google.com/analytics/devguides/collection/protocol/ga4/sending-events?client_type=gtag#recommended_parameters_for_reports
if (!params.session_id) {
params.session_id = await this.getOrCreateSessionId();
}
if (!params.engagement_time_msec) {
params.engagement_time_msec = DEFAULT_ENGAGEMENT_TIME_MSEC;
}
try {
const response = await fetch(
`${
this.debug ? GA_DEBUG_ENDPOINT : GA_ENDPOINT
}?measurement_id=${MEASUREMENT_ID}&api_secret=${API_SECRET}`,
{
method: 'POST',
body: JSON.stringify({
client_id: await this.getOrCreateClientId(),
events: [
{
name,
params
}
]
})
}
);
if (!this.debug) {
return;
}
console.log(await response.text());
} catch (e) {
console.error('Google Analytics request failed with an exception', e);
}
}
// Fire a page view event.
async firePageViewEvent(pageTitle, pageLocation, additionalParams = {}) {
return this.fireEvent('page_view', {
page_title: pageTitle,
page_location: pageLocation,
...additionalParams
});
}
// Fire an error event.
async fireErrorEvent(error, additionalParams = {}) {
// Note: 'error' is a reserved event name and cannot be used
// see https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference?client_type=gtag#reserved_names
return this.fireEvent('extension_error', {
...error,
...additionalParams
});
}
}
export default new Analytics();