forked from meecodebymariomurrent/expo-analytics
-
Notifications
You must be signed in to change notification settings - Fork 0
/
analytics.js
155 lines (131 loc) · 5.77 KB
/
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import {Platform, Dimensions} from 'react-native';
import Constants from 'expo-constants';
import * as Application from 'expo-application';
import {Serializable} from './hits';
const {width, height} = Dimensions.get('window');
let defaultOptions = {debug: false};
let webViewUserAgent = null;
const getWebViewUserAgent = async (options) => {
return new Promise((resolve) => {
if (options.userAgent) {
webViewUserAgent = options.userAgent;
return resolve(options.userAgent);
}
if (webViewUserAgent) return resolve(webViewUserAgent);
Constants.getWebViewUserAgentAsync()
.then(userAgent => {
webViewUserAgent = userAgent;
resolve(userAgent);
})
.catch(() => resolve('unknown user agent'))
});
}
export default class Analytics {
customDimensions = []
customMetrics = []
constructor(propertyId, clientId, additionalParameters = {}, options = defaultOptions) {
this.propertyId = propertyId;
this.options = options;
this.clientId = clientId;
let {an, aid, av} = additionalParameters
if (Application.applicationName && Application.applicationId && Application.nativeApplicationVersion) {
an = an ? an : Application.applicationName
aid = aid ? aid : Application.applicationId
av = av ? av : Application.nativeApplicationVersion
} else if (!an || !aid || !av) {
console.warn(`It looks like you're in the bare workflow and haven't supplied 'an', 'aid' or 'av' as additional parameters.`)
}
this.parameters = {
an,
aid,
av,
sr: `${width}x${height}`,
...additionalParameters
};
this.promiseGetWebViewUserAgentAsync = getWebViewUserAgent(options)
.then(userAgent => {
this.userAgent = userAgent;
if (this.options.debug) {
console.log(`[expo-analytics] UserAgent=${userAgent}`);
console.log(`[expo-analytics] Additional parameters=`, this.parameters);
}
});
}
hit(hit) {
// send only after the user agent is saved
return this.promiseGetWebViewUserAgentAsync
.then(() => this.send(hit));
}
event(event) {
// send only after the user agent is saved
return this.promiseGetWebViewUserAgentAsync
.then(() => this.send(event));
}
addParameter(name, value) {
this.parameters[name] = value;
}
addCustomDimension(index, value) {
this.customDimensions[index] = value;
}
removeCustomDimension(index) {
delete this.customDimensions[index];
}
addCustomMetric(index, value) {
this.customMetrics[index] = value;
}
removeCustomMetric(index) {
delete this.customMetrics[index];
}
send(hit) {
/* format: https://www.google-analytics.com/collect? +
* &tid= GA property ID (required)
* &v= GA protocol version (always 1) (required)
* &t= hit type (pageview / screenview)
* &dp= page name (if hit type is pageview)
* &cd= screen name (if hit type is screenview)
* &cid= anonymous client ID (optional if uid is given)
* &uid= user id (optional if cid is given)
* &ua= user agent override
* &an= app name (required for any of the other app parameters to work)
* &aid= app id
* &av= app version
* &sr= screen resolution
* &cd{n}= custom dimensions
* &cm{n}= custom metrics
* &z= cache buster (prevent browsers from caching GET requests -- should always be last)
*
* Ecommerce track support (transaction)
* &ti= transaction The transaction ID. (e.g. 1234)
* &ta= The store or affiliation from which this transaction occurred (e.g. Acme Clothing).
* &tr= Specifies the total revenue or grand total associated with the transaction (e.g. 11.99). This value may include shipping, tax costs, or other adjustments to total revenue that you want to include as part of your revenue calculations.
* &tt= Specifies the total shipping cost of the transaction. (e.g. 5)
*
* Ecommerce track support (addItem)
* &ti= transaction The transaction ID. (e.g. 1234)
* &in= The item name. (e.g. Fluffy Pink Bunnies)
* &ip= The individual, unit, price for each item. (e.g. 11.99)
* &iq= The number of units purchased in the transaction. If a non-integer value is passed into this field (e.g. 1.5), it will be rounded to the closest integer value.
* &ic= TSpecifies the SKU or item code. (e.g. SKU47)
* &iv= The category to which the item belongs (e.g. Party Toys)
*/
const customDimensions = this.customDimensions.map((value, index) => `cd${index}=${value}`).join('&');
const customMetrics = this.customMetrics.map((value, index) => `cm${index}=${value}`).join('&');
const params = new Serializable(this.parameters).toQueryString();
const url = `https://www.google-analytics.com/collect?tid=${this.propertyId}&v=1&cid=${this.clientId}&${hit.toQueryString()}&${params}&${customDimensions}&${customMetrics}&z=${Math.round(Math.random() * 1e8)}`;
//Keep original options if on mobile
let options = {
method: 'get',
headers: {
'User-Agent': this.userAgent,
}
};
if (Platform.OS === 'web') {
//Request opaque resources to avoid preflight CORS error in Safari
options.mode = 'no-cors';
}
if (this.options.debug) {
console.log(`[expo-analytics] Sending GET request to ${url}`);
}
return fetch(url, options);
}
}