swetrix 2.3.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -68,9 +68,33 @@
68
68
  var getUTMSource = function () { return findInSearch(utmSourceRegex); };
69
69
  var getUTMMedium = function () { return findInSearch(utmMediumRegex); };
70
70
  var getUTMCampaign = function () { return findInSearch(utmCampaignRegex); };
71
- var getPath = function () {
72
- // TODO: Maybe we should also include such data as location.hash or location.search
73
- return location.pathname || '';
71
+ /**
72
+ * Function used to track the current page (path) of the application.
73
+ * Will work in cases where the path looks like:
74
+ * - /path
75
+ * - /#/path
76
+ * - /path?search
77
+ * - /path?search#hash
78
+ * - /path#hash?search
79
+ *
80
+ * @param options - Options for the function.
81
+ * @param options.hash - Whether to trigger on hash change.
82
+ * @param options.search - Whether to trigger on search change.
83
+ * @returns The path of the current page.
84
+ */
85
+ var getPath = function (options) {
86
+ var result = location.pathname || '';
87
+ if (options.hash) {
88
+ var hashIndex = location.hash.indexOf('?');
89
+ var hashString = hashIndex > -1 ? location.hash.substring(0, hashIndex) : location.hash;
90
+ result += hashString;
91
+ }
92
+ if (options.search) {
93
+ var hashIndex = location.hash.indexOf('?');
94
+ var searchString = location.search || (hashIndex > -1 ? location.hash.substring(hashIndex) : '');
95
+ result += searchString;
96
+ }
97
+ return result;
74
98
  };
75
99
 
76
100
  var defaultPageActions = {
@@ -92,7 +116,7 @@
92
116
  if (!this.canTrack()) {
93
117
  return;
94
118
  }
95
- var data = __assign({ pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() }, event);
119
+ var data = __assign(__assign({}, event), { pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() });
96
120
  this.sendRequest('custom', data);
97
121
  };
98
122
  Lib.prototype.trackPageViews = function (options) {
@@ -103,15 +127,16 @@
103
127
  return this.pageData.actions;
104
128
  }
105
129
  this.pageViewsOptions = options;
106
- var hbInterval, interval;
130
+ var interval;
107
131
  if (!(options === null || options === void 0 ? void 0 : options.unique)) {
108
132
  interval = setInterval(this.trackPathChange, 2000);
109
133
  }
110
- if (!(options === null || options === void 0 ? void 0 : options.noHeartbeat)) {
111
- setTimeout(this.heartbeat, 3000);
112
- hbInterval = setInterval(this.heartbeat, 28000);
113
- }
114
- var path = getPath();
134
+ setTimeout(this.heartbeat, 3000);
135
+ var hbInterval = setInterval(this.heartbeat, 28000);
136
+ var path = getPath({
137
+ hash: options === null || options === void 0 ? void 0 : options.hash,
138
+ search: options === null || options === void 0 ? void 0 : options.search,
139
+ });
115
140
  this.pageData = {
116
141
  path: path,
117
142
  actions: {
@@ -136,23 +161,17 @@
136
161
  this.perfStatsCollected = true;
137
162
  return {
138
163
  // Network
139
- // @ts-ignore
140
- dns: perf.domainLookupEnd - perf.domainLookupStart,
141
- // @ts-ignore
142
- tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0,
143
- // @ts-ignore
144
- conn: perf.secureConnectionStart ? perf.secureConnectionStart - perf.connectStart : perf.connectEnd - perf.connectStart,
145
- // @ts-ignore
146
- response: perf.responseEnd - perf.responseStart,
164
+ dns: perf.domainLookupEnd - perf.domainLookupStart, // DNS Resolution
165
+ tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0, // TLS Setup; checking if secureConnectionStart is not 0 (it's 0 for non-https websites)
166
+ conn: perf.secureConnectionStart
167
+ ? perf.secureConnectionStart - perf.connectStart
168
+ : perf.connectEnd - perf.connectStart, // Connection time
169
+ response: perf.responseEnd - perf.responseStart, // Response Time (Download)
147
170
  // Frontend
148
- // @ts-ignore
149
- render: perf.domComplete - perf.domContentLoadedEventEnd,
150
- // @ts-ignore
151
- dom_load: perf.domContentLoadedEventEnd - perf.responseEnd,
152
- // @ts-ignore
153
- page_load: perf.loadEventStart,
171
+ render: perf.domComplete - perf.domContentLoadedEventEnd, // Browser rendering the HTML time
172
+ dom_load: perf.domContentLoadedEventEnd - perf.responseEnd, // DOM loading timing
173
+ page_load: perf.loadEventStart, // Page load time
154
174
  // Backend
155
- // @ts-ignore
156
175
  ttfb: perf.responseStart - perf.requestStart,
157
176
  };
158
177
  };
@@ -166,40 +185,25 @@
166
185
  };
167
186
  this.sendRequest('hb', data);
168
187
  };
169
- Lib.prototype.checkIgnore = function (path) {
170
- var _a;
171
- var ignore = (_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.ignore;
172
- if (Array.isArray(ignore)) {
173
- for (var i = 0; i < ignore.length; ++i) {
174
- if (ignore[i] === path)
175
- return true;
176
- // @ts-ignore
177
- if (ignore[i] instanceof RegExp && ignore[i].test(path))
178
- return true;
179
- }
180
- }
181
- return false;
182
- };
183
188
  // Tracking path changes. If path changes -> calling this.trackPage method
184
189
  Lib.prototype.trackPathChange = function () {
190
+ var _a, _b;
185
191
  if (!this.pageData)
186
192
  return;
187
- var newPath = getPath();
193
+ var newPath = getPath({
194
+ hash: (_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.hash,
195
+ search: (_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.search,
196
+ });
188
197
  var path = this.pageData.path;
189
198
  if (path !== newPath) {
190
199
  this.trackPage(newPath, false);
191
200
  }
192
201
  };
193
202
  Lib.prototype.getPreviousPage = function () {
194
- var _a, _b;
195
203
  // Assuming that this function is called in trackPage and this.activePage is not overwritten by new value yet
196
204
  // That method of getting previous page works for SPA websites
197
205
  if (this.activePage) {
198
- var shouldIgnore = this.checkIgnore(this.activePage);
199
- if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise)) {
200
- return null;
201
- }
202
- return shouldIgnore ? null : this.activePage;
206
+ return this.activePage;
203
207
  }
204
208
  // Checking if URL is supported by the browser (for example, IE11 does not support it)
205
209
  if (typeof URL === 'function') {
@@ -215,73 +219,60 @@
215
219
  if (host !== refHost) {
216
220
  return null;
217
221
  }
218
- var shouldIgnore = this.checkIgnore(pathname);
219
- if (shouldIgnore && ((_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.doNotAnonymise)) {
220
- return null;
221
- }
222
- return shouldIgnore ? null : pathname;
222
+ return pathname;
223
223
  }
224
- catch (_c) {
224
+ catch (_a) {
225
225
  return null;
226
226
  }
227
227
  }
228
228
  return null;
229
229
  };
230
230
  Lib.prototype.trackPage = function (pg, unique) {
231
- var _a, _b;
232
231
  if (unique === void 0) { unique = false; }
233
232
  if (!this.pageData)
234
233
  return;
235
234
  this.pageData.path = pg;
236
- var shouldIgnore = this.checkIgnore(pg);
237
- if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise))
238
- return;
239
235
  var perf = this.getPerformanceStats();
240
- var prev;
241
- if (!((_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.noUserFlow)) {
242
- prev = this.getPreviousPage();
243
- }
244
- var data = {
236
+ var prev = this.getPreviousPage();
237
+ this.activePage = pg;
238
+ this.submitPageView(pg, prev, unique, perf, true);
239
+ };
240
+ Lib.prototype.submitPageView = function (pg, prev, unique, perf, evokeCallback) {
241
+ var _a;
242
+ var privateData = {
245
243
  pid: this.projectID,
244
+ perf: perf,
245
+ unique: unique,
246
+ };
247
+ var pvPayload = {
246
248
  lc: getLocale(),
247
249
  tz: getTimezone(),
248
250
  ref: getReferrer(),
249
251
  so: getUTMSource(),
250
252
  me: getUTMMedium(),
251
253
  ca: getUTMCampaign(),
252
- unique: unique,
253
- pg: shouldIgnore ? null : pg,
254
- perf: perf,
254
+ pg: pg,
255
255
  prev: prev,
256
256
  };
257
- this.activePage = pg;
258
- this.sendRequest('', data);
259
- };
260
- Lib.prototype.debug = function (message) {
261
- var _a;
262
- if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.debug) {
263
- console.log('[Swetrix]', message);
257
+ if (evokeCallback && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.callback)) {
258
+ var callbackResult = this.pageViewsOptions.callback(pvPayload);
259
+ if (callbackResult === false) {
260
+ return;
261
+ }
262
+ if (callbackResult && typeof callbackResult === 'object') {
263
+ Object.assign(pvPayload, callbackResult);
264
+ }
264
265
  }
266
+ Object.assign(pvPayload, privateData);
267
+ this.sendRequest('', pvPayload);
265
268
  };
266
269
  Lib.prototype.canTrack = function () {
267
270
  var _a, _b, _c, _d;
268
- if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled) {
269
- this.debug('Tracking disabled: the \'disabled\' setting is set to true.');
270
- return false;
271
- }
272
- if (!isInBrowser()) {
273
- this.debug('Tracking disabled: script does not run in browser environment.');
274
- return false;
275
- }
276
- if (((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') {
277
- this.debug('Tracking disabled: respecting user\'s \'Do Not Track\' preference.');
278
- return false;
279
- }
280
- if (!((_d = this.options) === null || _d === void 0 ? void 0 : _d.debug) && isLocalhost()) {
281
- return false;
282
- }
283
- if (isAutomated()) {
284
- this.debug('Tracking disabled: navigation is automated by WebDriver.');
271
+ if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled) ||
272
+ !isInBrowser() ||
273
+ (((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') ||
274
+ (!((_d = this.options) === null || _d === void 0 ? void 0 : _d.devMode) && isLocalhost()) ||
275
+ isAutomated()) {
285
276
  return false;
286
277
  }
287
278
  return true;
@@ -349,9 +340,24 @@
349
340
  }
350
341
  });
351
342
  }
343
+ /**
344
+ * This function is used to manually track a page view event.
345
+ * It's useful if your application uses esoteric routing which is not supported by Swetrix by default.
346
+ *
347
+ * @param path Path of the page to track (this will be sent to the Swetrix API and displayed in the dashboard).
348
+ * @param prev Path of the previous page.
349
+ * @param unique If set to `true`, only 1 event with the same ID will be saved per user session.
350
+ * @returns void
351
+ */
352
+ function trackPageview(path, prev, unique) {
353
+ if (!exports.LIB_INSTANCE)
354
+ return;
355
+ exports.LIB_INSTANCE.submitPageView(path, prev || null, Boolean(unique), {});
356
+ }
352
357
 
353
358
  exports.init = init;
354
359
  exports.track = track;
360
+ exports.trackPageview = trackPageview;
355
361
  exports.trackViews = trackViews;
356
362
 
357
363
  Object.defineProperty(exports, '__esModule', { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swetrix",
3
- "version": "2.3.1",
3
+ "version": "3.0.0",
4
4
  "description": "The JavaScript analytics client for Swetrix Analytics",
5
5
  "main": "dist/swetrix.cjs.js",
6
6
  "module": "dist/swetrix.es5.js",
@@ -32,13 +32,13 @@
32
32
  "bugs": {
33
33
  "url": "https://github.com/Swetrix/swetrix-js/issues"
34
34
  },
35
- "homepage": "https://swetrix.com/docs",
35
+ "homepage": "https://docs.swetrix.com",
36
36
  "dependencies": {
37
- "@types/node": "^20.8.6",
37
+ "@types/node": "^20.11.8",
38
38
  "tslib": "^2.6.2"
39
39
  },
40
40
  "devDependencies": {
41
- "@rollup/plugin-commonjs": "^25.0.5",
41
+ "@rollup/plugin-commonjs": "^25.0.7",
42
42
  "@rollup/plugin-node-resolve": "^15.2.3",
43
43
  "rimraf": "^4.4.1",
44
44
  "rollup": "^2.79.1",
@@ -46,6 +46,6 @@
46
46
  "rollup-plugin-sourcemaps": "^0.6.3",
47
47
  "rollup-plugin-typescript2": "^0.36.0",
48
48
  "rollup-plugin-uglify": "^6.0.4",
49
- "typescript": "^5.2.2"
49
+ "typescript": "^5.3.3"
50
50
  }
51
51
  }
package/src/Lib.ts CHANGED
@@ -1,13 +1,21 @@
1
1
  import {
2
- isInBrowser, isLocalhost, isAutomated, getLocale, getTimezone, getReferrer,
3
- getUTMCampaign, getUTMMedium, getUTMSource, getPath,
2
+ isInBrowser,
3
+ isLocalhost,
4
+ isAutomated,
5
+ getLocale,
6
+ getTimezone,
7
+ getReferrer,
8
+ getUTMCampaign,
9
+ getUTMMedium,
10
+ getUTMSource,
11
+ getPath,
4
12
  } from './utils'
5
13
 
6
14
  export interface LibOptions {
7
15
  /**
8
- * When set to `true`, all tracking logs will be printed to console and localhost events will be sent to server.
16
+ * When set to `true`, localhost events will be sent to server.
9
17
  */
10
- debug?: boolean
18
+ devMode?: boolean
11
19
 
12
20
  /**
13
21
  * When set to `true`, the tracking library won't send any data to server.
@@ -37,6 +45,29 @@ export interface TrackEventOptions {
37
45
  }
38
46
  }
39
47
 
48
+ // Partial user-editable pageview payload
49
+ export interface IPageViewPayload {
50
+ lc: string | undefined
51
+ tz: string | undefined
52
+ ref: string | undefined
53
+ so: string | undefined
54
+ me: string | undefined
55
+ ca: string | undefined
56
+ pg: string
57
+ prev: string | null | undefined
58
+ }
59
+
60
+ interface IPerfPayload {
61
+ dns: number
62
+ tls: number
63
+ conn: number
64
+ response: number
65
+ render: number
66
+ dom_load: number
67
+ page_load: number
68
+ ttfb: number
69
+ }
70
+
40
71
  /**
41
72
  * The object returned by `trackPageViews()`, used to stop tracking pages.
42
73
  */
@@ -60,20 +91,28 @@ export interface PageViewsOptions {
60
91
  */
61
92
  unique?: boolean
62
93
 
63
- /** A list of Regular Expressions or string pathes to ignore. */
64
- ignore?: Array<string | RegExp>
65
-
66
- /** Do not send paths from ignore list to API. If set to `false`, the page view information will be sent to the Swetrix API, but the page will be displayed as a 'Redacted page' in the dashboard. */
67
- doNotAnonymise?: boolean
68
-
69
- /** Do not send Heartbeat requests to the server. */
70
- noHeartbeat?: boolean
71
-
72
94
  /** Send Heartbeat requests when the website tab is not active in the browser. */
73
95
  heartbeatOnBackground?: boolean
74
96
 
75
- /** Disable user-flow */
76
- noUserFlow?: boolean
97
+ /**
98
+ * Set to `true` to enable hash-based routing.
99
+ * For example if you have pages like /#/path or want to track pages like /path#hash
100
+ */
101
+ hash?: boolean
102
+
103
+ /**
104
+ * Set to `true` to enable search-based routing.
105
+ * For example if you have pages like /path?search
106
+ */
107
+ search?: boolean
108
+
109
+ /**
110
+ * Callback to edit / prevent sending pageviews.
111
+ *
112
+ * @param payload - The pageview payload.
113
+ * @returns The edited payload or `false` to prevent sending the pageview. If `true` is returned, the payload will be sent as-is.
114
+ */
115
+ callback?: (payload: IPageViewPayload) => IPageViewPayload | boolean
77
116
  }
78
117
 
79
118
  export const defaultPageActions = {
@@ -99,6 +138,7 @@ export class Lib {
99
138
  }
100
139
 
101
140
  const data = {
141
+ ...event,
102
142
  pid: this.projectID,
103
143
  pg: this.activePage,
104
144
  lc: getLocale(),
@@ -107,7 +147,6 @@ export class Lib {
107
147
  so: getUTMSource(),
108
148
  me: getUTMMedium(),
109
149
  ca: getUTMCampaign(),
110
- ...event,
111
150
  }
112
151
  this.sendRequest('custom', data)
113
152
  }
@@ -122,17 +161,19 @@ export class Lib {
122
161
  }
123
162
 
124
163
  this.pageViewsOptions = options
125
- let hbInterval: NodeJS.Timeout, interval: NodeJS.Timeout
164
+ let interval: NodeJS.Timeout
165
+
126
166
  if (!options?.unique) {
127
167
  interval = setInterval(this.trackPathChange, 2000)
128
168
  }
129
169
 
130
- if (!options?.noHeartbeat) {
131
- setTimeout(this.heartbeat, 3000)
132
- hbInterval = setInterval(this.heartbeat, 28000)
133
- }
170
+ setTimeout(this.heartbeat, 3000)
171
+ const hbInterval = setInterval(this.heartbeat, 28000)
134
172
 
135
- const path = getPath()
173
+ const path = getPath({
174
+ hash: options?.hash,
175
+ search: options?.search,
176
+ })
136
177
 
137
178
  this.pageData = {
138
179
  path,
@@ -148,12 +189,12 @@ export class Lib {
148
189
  return this.pageData.actions
149
190
  }
150
191
 
151
- getPerformanceStats(): object {
192
+ getPerformanceStats(): IPerfPayload | {} {
152
193
  if (!this.canTrack() || this.perfStatsCollected || !window.performance?.getEntriesByType) {
153
194
  return {}
154
195
  }
155
196
 
156
- const perf = window.performance.getEntriesByType('navigation')[0]
197
+ const perf = window.performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming
157
198
 
158
199
  if (!perf) {
159
200
  return {}
@@ -163,25 +204,19 @@ export class Lib {
163
204
 
164
205
  return {
165
206
  // Network
166
- // @ts-ignore
167
207
  dns: perf.domainLookupEnd - perf.domainLookupStart, // DNS Resolution
168
- // @ts-ignore
169
208
  tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0, // TLS Setup; checking if secureConnectionStart is not 0 (it's 0 for non-https websites)
170
- // @ts-ignore
171
- conn: perf.secureConnectionStart ? perf.secureConnectionStart - perf.connectStart : perf.connectEnd - perf.connectStart, // Connection time
172
- // @ts-ignore
209
+ conn: perf.secureConnectionStart
210
+ ? perf.secureConnectionStart - perf.connectStart
211
+ : perf.connectEnd - perf.connectStart, // Connection time
173
212
  response: perf.responseEnd - perf.responseStart, // Response Time (Download)
174
213
 
175
214
  // Frontend
176
- // @ts-ignore
177
215
  render: perf.domComplete - perf.domContentLoadedEventEnd, // Browser rendering the HTML time
178
- // @ts-ignore
179
216
  dom_load: perf.domContentLoadedEventEnd - perf.responseEnd, // DOM loading timing
180
- // @ts-ignore
181
217
  page_load: perf.loadEventStart, // Page load time
182
218
 
183
219
  // Backend
184
- // @ts-ignore
185
220
  ttfb: perf.responseStart - perf.requestStart,
186
221
  }
187
222
  }
@@ -198,23 +233,13 @@ export class Lib {
198
233
  this.sendRequest('hb', data)
199
234
  }
200
235
 
201
- private checkIgnore(path: string): boolean {
202
- const ignore = this.pageViewsOptions?.ignore
203
-
204
- if (Array.isArray(ignore)) {
205
- for (let i = 0; i < ignore.length; ++i) {
206
- if (ignore[i] === path) return true
207
- // @ts-ignore
208
- if (ignore[i] instanceof RegExp && ignore[i].test(path)) return true
209
- }
210
- }
211
- return false
212
- }
213
-
214
236
  // Tracking path changes. If path changes -> calling this.trackPage method
215
237
  private trackPathChange(): void {
216
238
  if (!this.pageData) return
217
- const newPath = getPath()
239
+ const newPath = getPath({
240
+ hash: this.pageViewsOptions?.hash,
241
+ search: this.pageViewsOptions?.search,
242
+ })
218
243
  const { path } = this.pageData
219
244
 
220
245
  if (path !== newPath) {
@@ -226,13 +251,7 @@ export class Lib {
226
251
  // Assuming that this function is called in trackPage and this.activePage is not overwritten by new value yet
227
252
  // That method of getting previous page works for SPA websites
228
253
  if (this.activePage) {
229
- const shouldIgnore = this.checkIgnore(this.activePage)
230
-
231
- if (shouldIgnore && this.pageViewsOptions?.doNotAnonymise) {
232
- return null
233
- }
234
-
235
- return shouldIgnore ? null : this.activePage
254
+ return this.activePage
236
255
  }
237
256
 
238
257
  // Checking if URL is supported by the browser (for example, IE11 does not support it)
@@ -254,13 +273,7 @@ export class Lib {
254
273
  return null
255
274
  }
256
275
 
257
- const shouldIgnore = this.checkIgnore(pathname)
258
-
259
- if (shouldIgnore && this.pageViewsOptions?.doNotAnonymise) {
260
- return null
261
- }
262
-
263
- return shouldIgnore ? null : pathname
276
+ return pathname
264
277
  } catch {
265
278
  return null
266
279
  }
@@ -273,64 +286,62 @@ export class Lib {
273
286
  if (!this.pageData) return
274
287
  this.pageData.path = pg
275
288
 
276
- const shouldIgnore = this.checkIgnore(pg)
277
-
278
- if (shouldIgnore && this.pageViewsOptions?.doNotAnonymise) return
279
-
280
289
  const perf = this.getPerformanceStats()
281
290
 
282
- let prev
291
+ const prev = this.getPreviousPage()
283
292
 
284
- if (!this.pageViewsOptions?.noUserFlow) {
285
- prev = this.getPreviousPage()
286
- }
293
+ this.activePage = pg
294
+ this.submitPageView(pg, prev, unique, perf, true)
295
+ }
287
296
 
288
- const data = {
297
+ submitPageView(
298
+ pg: string,
299
+ prev: string | null | undefined,
300
+ unique: boolean,
301
+ perf: IPerfPayload | {},
302
+ evokeCallback?: boolean,
303
+ ): void {
304
+ const privateData = {
289
305
  pid: this.projectID,
306
+ perf,
307
+ unique,
308
+ }
309
+ const pvPayload = {
290
310
  lc: getLocale(),
291
311
  tz: getTimezone(),
292
312
  ref: getReferrer(),
293
313
  so: getUTMSource(),
294
314
  me: getUTMMedium(),
295
315
  ca: getUTMCampaign(),
296
- unique,
297
- pg: shouldIgnore ? null : pg,
298
- perf,
316
+ pg,
299
317
  prev,
300
318
  }
301
319
 
302
- this.activePage = pg
303
- this.sendRequest('', data)
304
- }
305
-
306
- private debug(message: string): void {
307
- if (this.options?.debug) {
308
- console.log('[Swetrix]', message)
309
- }
310
- }
320
+ if (evokeCallback && this.pageViewsOptions?.callback) {
321
+ const callbackResult = this.pageViewsOptions.callback(pvPayload)
311
322
 
312
- private canTrack(): boolean {
313
- if (this.options?.disabled) {
314
- this.debug('Tracking disabled: the \'disabled\' setting is set to true.')
315
- return false
316
- }
323
+ if (callbackResult === false) {
324
+ return
325
+ }
317
326
 
318
- if (!isInBrowser()) {
319
- this.debug('Tracking disabled: script does not run in browser environment.')
320
- return false
327
+ if (callbackResult && typeof callbackResult === 'object') {
328
+ Object.assign(pvPayload, callbackResult)
329
+ }
321
330
  }
322
331
 
323
- if (this.options?.respectDNT && window.navigator?.doNotTrack === '1') {
324
- this.debug('Tracking disabled: respecting user\'s \'Do Not Track\' preference.')
325
- return false
326
- }
332
+ Object.assign(pvPayload, privateData)
327
333
 
328
- if (!this.options?.debug && isLocalhost()) {
329
- return false
330
- }
334
+ this.sendRequest('', pvPayload)
335
+ }
331
336
 
332
- if (isAutomated()) {
333
- this.debug('Tracking disabled: navigation is automated by WebDriver.')
337
+ private canTrack(): boolean {
338
+ if (
339
+ this.options?.disabled ||
340
+ !isInBrowser() ||
341
+ (this.options?.respectDNT && window.navigator?.doNotTrack === '1') ||
342
+ (!this.options?.devMode && isLocalhost()) ||
343
+ isAutomated()
344
+ ) {
334
345
  return false
335
346
  }
336
347
 
package/src/index.ts CHANGED
@@ -1,6 +1,4 @@
1
- import {
2
- Lib, LibOptions, TrackEventOptions, PageViewsOptions, PageActions, defaultPageActions,
3
- } from './Lib'
1
+ import { Lib, LibOptions, TrackEventOptions, PageViewsOptions, PageActions, defaultPageActions } from './Lib'
4
2
 
5
3
  export let LIB_INSTANCE: Lib | null = null
6
4
 
@@ -58,3 +56,18 @@ export function trackViews(options?: PageViewsOptions): Promise<PageActions> {
58
56
  }
59
57
  })
60
58
  }
59
+
60
+ /**
61
+ * This function is used to manually track a page view event.
62
+ * It's useful if your application uses esoteric routing which is not supported by Swetrix by default.
63
+ *
64
+ * @param path Path of the page to track (this will be sent to the Swetrix API and displayed in the dashboard).
65
+ * @param prev Path of the previous page.
66
+ * @param unique If set to `true`, only 1 event with the same ID will be saved per user session.
67
+ * @returns void
68
+ */
69
+ export function trackPageview(path: string, prev?: string, unique?: boolean): void {
70
+ if (!LIB_INSTANCE) return
71
+
72
+ LIB_INSTANCE.submitPageView(path, prev || null, Boolean(unique), {})
73
+ }