(feature) Trackviews callback (#11)

* updated dependencies

* added prettier

* added types

* added callback to trackPageViews

* removed noUserFlow param

* removed noHeartbeat param

* debug -> devMode

* prevent possible internal values being overwritten by TrackEventOptions

* added callback desc

* build
This commit is contained in:
Andrii Romasiun
2024-01-29 21:54:55 +00:00
committed by GitHub
parent 05ff4c1b31
commit 4a116c5d3b
14 changed files with 302 additions and 453 deletions

13
.prettierrc.js Normal file
View File

@ -0,0 +1,13 @@
module.exports = {
printWidth: 120, // max 120 chars in line, code is easy to read
useTabs: false, // use spaces instead of tabs
tabWidth: 2, // "visual width" of of the "tab"
trailingComma: 'all', // add trailing commas in objects, arrays, etc.
semi: false, // Only add semicolons at the beginning of lines that may introduce ASI failures
singleQuote: true, // '' for stings instead of ""
bracketSpacing: true, // import { some } ... instead of import {some} ...
arrowParens: 'always', // braces even for single param in arrow functions (a) => { }
jsxSingleQuote: true, // '' for react props
bracketSameLine: false, // pretty JSX
endOfLine: 'lf', // 'lf' for linux, 'crlf' for windows, we need to use 'lf' for git
}

46
dist/esnext/Lib.d.ts vendored
View File

@ -1,8 +1,8 @@
export interface LibOptions {
/**
* When set to `true`, all tracking logs will be printed to console and localhost events will be sent to server.
* When set to `true`, localhost events will be sent to server.
*/
debug?: boolean;
devMode?: boolean;
/**
* When set to `true`, the tracking library won't send any data to server.
* Useful for development purposes when this value is set based on `.env` var.
@ -25,6 +25,26 @@ export interface TrackEventOptions {
[key: string]: string;
};
}
export interface IPageViewPayload {
lc: string | undefined;
tz: string | undefined;
ref: string | undefined;
so: string | undefined;
me: string | undefined;
ca: string | undefined;
pg: string;
prev: string | null | undefined;
}
interface IPerfPayload {
dns: number;
tls: number;
conn: number;
response: number;
render: number;
dom_load: number;
page_load: number;
ttfb: number;
}
/**
* The object returned by `trackPageViews()`, used to stop tracking pages.
*/
@ -44,16 +64,8 @@ export interface PageViewsOptions {
* This param is useful when tracking single-page landing websites.
*/
unique?: boolean;
/** A list of Regular Expressions or string pathes to ignore. */
ignore?: Array<string | RegExp>;
/** 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. */
doNotAnonymise?: boolean;
/** Do not send Heartbeat requests to the server. */
noHeartbeat?: boolean;
/** Send Heartbeat requests when the website tab is not active in the browser. */
heartbeatOnBackground?: boolean;
/** Disable user-flow */
noUserFlow?: boolean;
/**
* Set to `true` to enable hash-based routing.
* For example if you have pages like /#/path or want to track pages like /path#hash
@ -64,6 +76,13 @@ export interface PageViewsOptions {
* For example if you have pages like /path?search
*/
search?: boolean;
/**
* Callback to edit / prevent sending pageviews.
*
* @param payload - The pageview payload.
* @returns The edited payload or `false` to prevent sending the pageview. If `true` is returned, the payload will be sent as-is.
*/
callback?: (payload: IPageViewPayload) => IPageViewPayload | boolean;
}
export declare const defaultPageActions: {
stop(): void;
@ -78,14 +97,13 @@ export declare class Lib {
constructor(projectID: string, options?: LibOptions | undefined);
track(event: TrackEventOptions): void;
trackPageViews(options?: PageViewsOptions): PageActions;
getPerformanceStats(): object;
getPerformanceStats(): IPerfPayload | {};
private heartbeat;
private checkIgnore;
private trackPathChange;
private getPreviousPage;
private trackPage;
submitPageView(pg: null | string, prev: string | null | undefined, unique: boolean, perf: any): void;
private debug;
submitPageView(pg: string, prev: string | null | undefined, unique: boolean, perf: IPerfPayload | {}, evokeCallback?: boolean): void;
private canTrack;
private sendRequest;
}
export {};

116
dist/esnext/Lib.js vendored
View File

@ -19,6 +19,7 @@ export class Lib {
return;
}
const data = {
...event,
pid: this.projectID,
pg: this.activePage,
lc: getLocale(),
@ -27,7 +28,6 @@ export class Lib {
so: getUTMSource(),
me: getUTMMedium(),
ca: getUTMCampaign(),
...event,
};
this.sendRequest('custom', data);
}
@ -39,14 +39,12 @@ export class Lib {
return this.pageData.actions;
}
this.pageViewsOptions = options;
let hbInterval, interval;
let interval;
if (!options?.unique) {
interval = setInterval(this.trackPathChange, 2000);
}
if (!options?.noHeartbeat) {
setTimeout(this.heartbeat, 3000);
hbInterval = setInterval(this.heartbeat, 28000);
}
setTimeout(this.heartbeat, 3000);
const hbInterval = setInterval(this.heartbeat, 28000);
const path = getPath({
hash: options?.hash,
search: options?.search,
@ -74,23 +72,17 @@ export class Lib {
this.perfStatsCollected = true;
return {
// Network
// @ts-ignore
dns: perf.domainLookupEnd - perf.domainLookupStart,
// @ts-ignore
tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0,
// @ts-ignore
conn: perf.secureConnectionStart ? perf.secureConnectionStart - perf.connectStart : perf.connectEnd - perf.connectStart,
// @ts-ignore
response: perf.responseEnd - perf.responseStart,
dns: perf.domainLookupEnd - perf.domainLookupStart, // DNS Resolution
tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0, // TLS Setup; checking if secureConnectionStart is not 0 (it's 0 for non-https websites)
conn: perf.secureConnectionStart
? perf.secureConnectionStart - perf.connectStart
: perf.connectEnd - perf.connectStart, // Connection time
response: perf.responseEnd - perf.responseStart, // Response Time (Download)
// Frontend
// @ts-ignore
render: perf.domComplete - perf.domContentLoadedEventEnd,
// @ts-ignore
dom_load: perf.domContentLoadedEventEnd - perf.responseEnd,
// @ts-ignore
page_load: perf.loadEventStart,
render: perf.domComplete - perf.domContentLoadedEventEnd, // Browser rendering the HTML time
dom_load: perf.domContentLoadedEventEnd - perf.responseEnd, // DOM loading timing
page_load: perf.loadEventStart, // Page load time
// Backend
// @ts-ignore
ttfb: perf.responseStart - perf.requestStart,
};
}
@ -103,19 +95,6 @@ export class Lib {
};
this.sendRequest('hb', data);
}
checkIgnore(path) {
const ignore = this.pageViewsOptions?.ignore;
if (Array.isArray(ignore)) {
for (let i = 0; i < ignore.length; ++i) {
if (ignore[i] === path)
return true;
// @ts-ignore
if (ignore[i] instanceof RegExp && ignore[i].test(path))
return true;
}
}
return false;
}
// Tracking path changes. If path changes -> calling this.trackPage method
trackPathChange() {
if (!this.pageData)
@ -133,11 +112,7 @@ export class Lib {
// Assuming that this function is called in trackPage and this.activePage is not overwritten by new value yet
// That method of getting previous page works for SPA websites
if (this.activePage) {
const shouldIgnore = this.checkIgnore(this.activePage);
if (shouldIgnore && this.pageViewsOptions?.doNotAnonymise) {
return null;
}
return shouldIgnore ? null : this.activePage;
return this.activePage;
}
// Checking if URL is supported by the browser (for example, IE11 does not support it)
if (typeof URL === 'function') {
@ -153,11 +128,7 @@ export class Lib {
if (host !== refHost) {
return null;
}
const shouldIgnore = this.checkIgnore(pathname);
if (shouldIgnore && this.pageViewsOptions?.doNotAnonymise) {
return null;
}
return shouldIgnore ? null : pathname;
return pathname;
}
catch {
return null;
@ -169,56 +140,45 @@ export class Lib {
if (!this.pageData)
return;
this.pageData.path = pg;
const shouldIgnore = this.checkIgnore(pg);
if (shouldIgnore && this.pageViewsOptions?.doNotAnonymise)
return;
const perf = this.getPerformanceStats();
let prev;
if (!this.pageViewsOptions?.noUserFlow) {
prev = this.getPreviousPage();
}
const prev = this.getPreviousPage();
this.activePage = pg;
this.submitPageView(shouldIgnore ? null : pg, prev, unique, perf);
this.submitPageView(pg, prev, unique, perf, true);
}
submitPageView(pg, prev, unique, perf) {
const data = {
submitPageView(pg, prev, unique, perf, evokeCallback) {
const privateData = {
pid: this.projectID,
perf,
unique,
};
const pvPayload = {
lc: getLocale(),
tz: getTimezone(),
ref: getReferrer(),
so: getUTMSource(),
me: getUTMMedium(),
ca: getUTMCampaign(),
unique,
pg,
perf,
prev,
};
this.sendRequest('', data);
}
debug(message) {
if (this.options?.debug) {
console.log('[Swetrix]', message);
if (evokeCallback && this.pageViewsOptions?.callback) {
const callbackResult = this.pageViewsOptions.callback(pvPayload);
if (callbackResult === false) {
return;
}
if (callbackResult && typeof callbackResult === 'object') {
Object.assign(pvPayload, callbackResult);
}
}
Object.assign(pvPayload, privateData);
this.sendRequest('', pvPayload);
}
canTrack() {
if (this.options?.disabled) {
this.debug('Tracking disabled: the \'disabled\' setting is set to true.');
return false;
}
if (!isInBrowser()) {
this.debug('Tracking disabled: script does not run in browser environment.');
return false;
}
if (this.options?.respectDNT && window.navigator?.doNotTrack === '1') {
this.debug('Tracking disabled: respecting user\'s \'Do Not Track\' preference.');
return false;
}
if (!this.options?.debug && isLocalhost()) {
return false;
}
if (isAutomated()) {
this.debug('Tracking disabled: navigation is automated by WebDriver.');
if (this.options?.disabled ||
!isInBrowser() ||
(this.options?.respectDNT && window.navigator?.doNotTrack === '1') ||
(!this.options?.devMode && isLocalhost()) ||
isAutomated()) {
return false;
}
return true;

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
import { Lib, defaultPageActions, } from './Lib';
import { Lib, defaultPageActions } from './Lib';
export let LIB_INSTANCE = null;
/**
* Initialise the tracking library instance (other methods won't work if the library is not initialised).

View File

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,GAAG,EAAgE,kBAAkB,GACtF,MAAM,OAAO,CAAA;AAEd,MAAM,CAAC,IAAI,YAAY,GAAe,IAAI,CAAA;AAE1C;;;;;;GAMG;AACH,MAAM,UAAU,IAAI,CAAC,GAAW,EAAE,OAAoB;IACpD,IAAI,CAAC,YAAY,EAAE;QACjB,YAAY,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;KACrC;IAED,OAAO,YAAY,CAAA;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CAAC,KAAwB;IAC5C,IAAI,CAAC,YAAY;QAAE,OAAM;IAEzB,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,OAA0B;IACnD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,CAAC,YAAY,EAAE;YACjB,OAAO,CAAC,kBAAkB,CAAC,CAAA;YAC3B,OAAM;SACP;QAED,8GAA8G;QAC9G,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,CAAC,UAAU,KAAK,UAAU,EAAE;YACzE,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAA;SAC9C;aAAM;YACL,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE;gBACnC,aAAa;gBACb,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAA;YAC/C,CAAC,CAAC,CAAA;SACH;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,IAAa,EAAE,MAAgB;IACzE,IAAI,CAAC,YAAY;QAAE,OAAM;IAEzB,YAAY,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAA;AACtE,CAAC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAgE,kBAAkB,EAAE,MAAM,OAAO,CAAA;AAE7G,MAAM,CAAC,IAAI,YAAY,GAAe,IAAI,CAAA;AAE1C;;;;;;GAMG;AACH,MAAM,UAAU,IAAI,CAAC,GAAW,EAAE,OAAoB;IACpD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IACtC,CAAC;IAED,OAAO,YAAY,CAAA;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CAAC,KAAwB;IAC5C,IAAI,CAAC,YAAY;QAAE,OAAM;IAEzB,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;AAC3B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,OAA0B;IACnD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO,CAAC,kBAAkB,CAAC,CAAA;YAC3B,OAAM;QACR,CAAC;QAED,8GAA8G;QAC9G,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;YAC1E,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAA;QAC/C,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE;gBACnC,aAAa;gBACb,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAA;YAC/C,CAAC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,IAAa,EAAE,MAAgB;IACzE,IAAI,CAAC,YAAY;QAAE,OAAM;IAEzB,YAAY,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAA;AACtE,CAAC"}

View File

@ -1 +1 @@
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAKA,MAAM,YAAY,GAAG,CAAC,GAAW,EAAsB,EAAE;IACvD,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACtC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAA;AACrC,CAAC,CAAA;AAED,MAAM,cAAc,GAAG,sCAAsC,CAAA;AAC7D,MAAM,gBAAgB,GAAG,6BAA6B,CAAA;AACtD,MAAM,cAAc,GAAG,2BAA2B,CAAA;AAElD,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,EAAE;IAC9B,OAAO,OAAO,MAAM,KAAK,WAAW,CAAA;AACtC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,EAAE;IAC9B,OAAO,QAAQ,EAAE,QAAQ,KAAK,WAAW,IAAI,QAAQ,EAAE,QAAQ,KAAK,WAAW,IAAI,QAAQ,EAAE,QAAQ,KAAK,EAAE,CAAA;AAC9G,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,EAAE;IAC9B,OAAO,SAAS,EAAE,SAAS,CAAA;AAC7B,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,EAAE;IAC5B,OAAO,OAAO,SAAS,CAAC,SAAS,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAA;AACjG,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,EAAE;IAC9B,IAAI;QACF,OAAO,IAAI,CAAC,cAAc,EAAE,CAAC,eAAe,EAAE,CAAC,QAAQ,CAAA;KACxD;IAAC,OAAO,CAAC,EAAE;QACV,OAAM;KACP;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,GAAuB,EAAE;IAClD,OAAO,QAAQ,CAAC,QAAQ,IAAI,SAAS,CAAA;AACvC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,cAAc,CAAC,CAAA;AAE9D,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,cAAc,CAAC,CAAA;AAE9D,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAA;AAElE;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,OAAiB,EAAU,EAAE;IACnD,IAAI,MAAM,GAAG,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAA;IAEpC,IAAI,OAAO,CAAC,IAAI,EAAE;QAChB,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAC5C,MAAM,UAAU,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAA;QACzF,MAAM,IAAI,UAAU,CAAA;KACrB;IAED,IAAI,OAAO,CAAC,MAAM,EAAE;QAClB,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAC5C,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QAClG,MAAM,IAAI,YAAY,CAAA;KACvB;IAED,OAAO,MAAM,CAAA;AACf,CAAC,CAAA"}
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"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"}

123
dist/swetrix.cjs.js vendored
View File

@ -114,7 +114,7 @@ var Lib = /** @class */ (function () {
if (!this.canTrack()) {
return;
}
var data = __assign({ pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() }, event);
var data = __assign(__assign({}, event), { pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() });
this.sendRequest('custom', data);
};
Lib.prototype.trackPageViews = function (options) {
@ -125,14 +125,12 @@ var Lib = /** @class */ (function () {
return this.pageData.actions;
}
this.pageViewsOptions = options;
var hbInterval, interval;
var interval;
if (!(options === null || options === void 0 ? void 0 : options.unique)) {
interval = setInterval(this.trackPathChange, 2000);
}
if (!(options === null || options === void 0 ? void 0 : options.noHeartbeat)) {
setTimeout(this.heartbeat, 3000);
hbInterval = setInterval(this.heartbeat, 28000);
}
setTimeout(this.heartbeat, 3000);
var hbInterval = setInterval(this.heartbeat, 28000);
var path = getPath({
hash: options === null || options === void 0 ? void 0 : options.hash,
search: options === null || options === void 0 ? void 0 : options.search,
@ -161,23 +159,17 @@ var Lib = /** @class */ (function () {
this.perfStatsCollected = true;
return {
// Network
// @ts-ignore
dns: perf.domainLookupEnd - perf.domainLookupStart,
// @ts-ignore
tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0,
// @ts-ignore
conn: perf.secureConnectionStart ? perf.secureConnectionStart - perf.connectStart : perf.connectEnd - perf.connectStart,
// @ts-ignore
response: perf.responseEnd - perf.responseStart,
dns: perf.domainLookupEnd - perf.domainLookupStart, // DNS Resolution
tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0, // TLS Setup; checking if secureConnectionStart is not 0 (it's 0 for non-https websites)
conn: perf.secureConnectionStart
? perf.secureConnectionStart - perf.connectStart
: perf.connectEnd - perf.connectStart, // Connection time
response: perf.responseEnd - perf.responseStart, // Response Time (Download)
// Frontend
// @ts-ignore
render: perf.domComplete - perf.domContentLoadedEventEnd,
// @ts-ignore
dom_load: perf.domContentLoadedEventEnd - perf.responseEnd,
// @ts-ignore
page_load: perf.loadEventStart,
render: perf.domComplete - perf.domContentLoadedEventEnd, // Browser rendering the HTML time
dom_load: perf.domContentLoadedEventEnd - perf.responseEnd, // DOM loading timing
page_load: perf.loadEventStart, // Page load time
// Backend
// @ts-ignore
ttfb: perf.responseStart - perf.requestStart,
};
};
@ -191,20 +183,6 @@ var Lib = /** @class */ (function () {
};
this.sendRequest('hb', data);
};
Lib.prototype.checkIgnore = function (path) {
var _a;
var ignore = (_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.ignore;
if (Array.isArray(ignore)) {
for (var i = 0; i < ignore.length; ++i) {
if (ignore[i] === path)
return true;
// @ts-ignore
if (ignore[i] instanceof RegExp && ignore[i].test(path))
return true;
}
}
return false;
};
// Tracking path changes. If path changes -> calling this.trackPage method
Lib.prototype.trackPathChange = function () {
var _a, _b;
@ -220,15 +198,10 @@ var Lib = /** @class */ (function () {
}
};
Lib.prototype.getPreviousPage = function () {
var _a, _b;
// Assuming that this function is called in trackPage and this.activePage is not overwritten by new value yet
// That method of getting previous page works for SPA websites
if (this.activePage) {
var shouldIgnore = this.checkIgnore(this.activePage);
if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise)) {
return null;
}
return shouldIgnore ? null : this.activePage;
return this.activePage;
}
// Checking if URL is supported by the browser (for example, IE11 does not support it)
if (typeof URL === 'function') {
@ -244,76 +217,60 @@ var Lib = /** @class */ (function () {
if (host !== refHost) {
return null;
}
var shouldIgnore = this.checkIgnore(pathname);
if (shouldIgnore && ((_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.doNotAnonymise)) {
return null;
}
return shouldIgnore ? null : pathname;
return pathname;
}
catch (_c) {
catch (_a) {
return null;
}
}
return null;
};
Lib.prototype.trackPage = function (pg, unique) {
var _a, _b;
if (unique === void 0) { unique = false; }
if (!this.pageData)
return;
this.pageData.path = pg;
var shouldIgnore = this.checkIgnore(pg);
if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise))
return;
var perf = this.getPerformanceStats();
var prev;
if (!((_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.noUserFlow)) {
prev = this.getPreviousPage();
}
var prev = this.getPreviousPage();
this.activePage = pg;
this.submitPageView(shouldIgnore ? null : pg, prev, unique, perf);
this.submitPageView(pg, prev, unique, perf, true);
};
Lib.prototype.submitPageView = function (pg, prev, unique, perf) {
var data = {
Lib.prototype.submitPageView = function (pg, prev, unique, perf, evokeCallback) {
var _a;
var privateData = {
pid: this.projectID,
perf: perf,
unique: unique,
};
var pvPayload = {
lc: getLocale(),
tz: getTimezone(),
ref: getReferrer(),
so: getUTMSource(),
me: getUTMMedium(),
ca: getUTMCampaign(),
unique: unique,
pg: pg,
perf: perf,
prev: prev,
};
this.sendRequest('', data);
};
Lib.prototype.debug = function (message) {
var _a;
if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.debug) {
console.log('[Swetrix]', message);
if (evokeCallback && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.callback)) {
var callbackResult = this.pageViewsOptions.callback(pvPayload);
if (callbackResult === false) {
return;
}
if (callbackResult && typeof callbackResult === 'object') {
Object.assign(pvPayload, callbackResult);
}
}
Object.assign(pvPayload, privateData);
this.sendRequest('', pvPayload);
};
Lib.prototype.canTrack = function () {
var _a, _b, _c, _d;
if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled) {
this.debug('Tracking disabled: the \'disabled\' setting is set to true.');
return false;
}
if (!isInBrowser()) {
this.debug('Tracking disabled: script does not run in browser environment.');
return false;
}
if (((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') {
this.debug('Tracking disabled: respecting user\'s \'Do Not Track\' preference.');
return false;
}
if (!((_d = this.options) === null || _d === void 0 ? void 0 : _d.debug) && isLocalhost()) {
return false;
}
if (isAutomated()) {
this.debug('Tracking disabled: navigation is automated by WebDriver.');
if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled) ||
!isInBrowser() ||
(((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') ||
(!((_d = this.options) === null || _d === void 0 ? void 0 : _d.devMode) && isLocalhost()) ||
isAutomated()) {
return false;
}
return true;

123
dist/swetrix.es5.js vendored
View File

@ -110,7 +110,7 @@ var Lib = /** @class */ (function () {
if (!this.canTrack()) {
return;
}
var data = __assign({ pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() }, event);
var data = __assign(__assign({}, event), { pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() });
this.sendRequest('custom', data);
};
Lib.prototype.trackPageViews = function (options) {
@ -121,14 +121,12 @@ var Lib = /** @class */ (function () {
return this.pageData.actions;
}
this.pageViewsOptions = options;
var hbInterval, interval;
var interval;
if (!(options === null || options === void 0 ? void 0 : options.unique)) {
interval = setInterval(this.trackPathChange, 2000);
}
if (!(options === null || options === void 0 ? void 0 : options.noHeartbeat)) {
setTimeout(this.heartbeat, 3000);
hbInterval = setInterval(this.heartbeat, 28000);
}
setTimeout(this.heartbeat, 3000);
var hbInterval = setInterval(this.heartbeat, 28000);
var path = getPath({
hash: options === null || options === void 0 ? void 0 : options.hash,
search: options === null || options === void 0 ? void 0 : options.search,
@ -157,23 +155,17 @@ var Lib = /** @class */ (function () {
this.perfStatsCollected = true;
return {
// Network
// @ts-ignore
dns: perf.domainLookupEnd - perf.domainLookupStart,
// @ts-ignore
tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0,
// @ts-ignore
conn: perf.secureConnectionStart ? perf.secureConnectionStart - perf.connectStart : perf.connectEnd - perf.connectStart,
// @ts-ignore
response: perf.responseEnd - perf.responseStart,
dns: perf.domainLookupEnd - perf.domainLookupStart, // DNS Resolution
tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0, // TLS Setup; checking if secureConnectionStart is not 0 (it's 0 for non-https websites)
conn: perf.secureConnectionStart
? perf.secureConnectionStart - perf.connectStart
: perf.connectEnd - perf.connectStart, // Connection time
response: perf.responseEnd - perf.responseStart, // Response Time (Download)
// Frontend
// @ts-ignore
render: perf.domComplete - perf.domContentLoadedEventEnd,
// @ts-ignore
dom_load: perf.domContentLoadedEventEnd - perf.responseEnd,
// @ts-ignore
page_load: perf.loadEventStart,
render: perf.domComplete - perf.domContentLoadedEventEnd, // Browser rendering the HTML time
dom_load: perf.domContentLoadedEventEnd - perf.responseEnd, // DOM loading timing
page_load: perf.loadEventStart, // Page load time
// Backend
// @ts-ignore
ttfb: perf.responseStart - perf.requestStart,
};
};
@ -187,20 +179,6 @@ var Lib = /** @class */ (function () {
};
this.sendRequest('hb', data);
};
Lib.prototype.checkIgnore = function (path) {
var _a;
var ignore = (_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.ignore;
if (Array.isArray(ignore)) {
for (var i = 0; i < ignore.length; ++i) {
if (ignore[i] === path)
return true;
// @ts-ignore
if (ignore[i] instanceof RegExp && ignore[i].test(path))
return true;
}
}
return false;
};
// Tracking path changes. If path changes -> calling this.trackPage method
Lib.prototype.trackPathChange = function () {
var _a, _b;
@ -216,15 +194,10 @@ var Lib = /** @class */ (function () {
}
};
Lib.prototype.getPreviousPage = function () {
var _a, _b;
// Assuming that this function is called in trackPage and this.activePage is not overwritten by new value yet
// That method of getting previous page works for SPA websites
if (this.activePage) {
var shouldIgnore = this.checkIgnore(this.activePage);
if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise)) {
return null;
}
return shouldIgnore ? null : this.activePage;
return this.activePage;
}
// Checking if URL is supported by the browser (for example, IE11 does not support it)
if (typeof URL === 'function') {
@ -240,76 +213,60 @@ var Lib = /** @class */ (function () {
if (host !== refHost) {
return null;
}
var shouldIgnore = this.checkIgnore(pathname);
if (shouldIgnore && ((_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.doNotAnonymise)) {
return null;
}
return shouldIgnore ? null : pathname;
return pathname;
}
catch (_c) {
catch (_a) {
return null;
}
}
return null;
};
Lib.prototype.trackPage = function (pg, unique) {
var _a, _b;
if (unique === void 0) { unique = false; }
if (!this.pageData)
return;
this.pageData.path = pg;
var shouldIgnore = this.checkIgnore(pg);
if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise))
return;
var perf = this.getPerformanceStats();
var prev;
if (!((_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.noUserFlow)) {
prev = this.getPreviousPage();
}
var prev = this.getPreviousPage();
this.activePage = pg;
this.submitPageView(shouldIgnore ? null : pg, prev, unique, perf);
this.submitPageView(pg, prev, unique, perf, true);
};
Lib.prototype.submitPageView = function (pg, prev, unique, perf) {
var data = {
Lib.prototype.submitPageView = function (pg, prev, unique, perf, evokeCallback) {
var _a;
var privateData = {
pid: this.projectID,
perf: perf,
unique: unique,
};
var pvPayload = {
lc: getLocale(),
tz: getTimezone(),
ref: getReferrer(),
so: getUTMSource(),
me: getUTMMedium(),
ca: getUTMCampaign(),
unique: unique,
pg: pg,
perf: perf,
prev: prev,
};
this.sendRequest('', data);
};
Lib.prototype.debug = function (message) {
var _a;
if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.debug) {
console.log('[Swetrix]', message);
if (evokeCallback && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.callback)) {
var callbackResult = this.pageViewsOptions.callback(pvPayload);
if (callbackResult === false) {
return;
}
if (callbackResult && typeof callbackResult === 'object') {
Object.assign(pvPayload, callbackResult);
}
}
Object.assign(pvPayload, privateData);
this.sendRequest('', pvPayload);
};
Lib.prototype.canTrack = function () {
var _a, _b, _c, _d;
if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled) {
this.debug('Tracking disabled: the \'disabled\' setting is set to true.');
return false;
}
if (!isInBrowser()) {
this.debug('Tracking disabled: script does not run in browser environment.');
return false;
}
if (((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') {
this.debug('Tracking disabled: respecting user\'s \'Do Not Track\' preference.');
return false;
}
if (!((_d = this.options) === null || _d === void 0 ? void 0 : _d.debug) && isLocalhost()) {
return false;
}
if (isAutomated()) {
this.debug('Tracking disabled: navigation is automated by WebDriver.');
if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled) ||
!isInBrowser() ||
(((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') ||
(!((_d = this.options) === null || _d === void 0 ? void 0 : _d.devMode) && isLocalhost()) ||
isAutomated()) {
return false;
}
return true;

2
dist/swetrix.js vendored

File diff suppressed because one or more lines are too long

123
dist/swetrix.orig.js vendored
View File

@ -116,7 +116,7 @@
if (!this.canTrack()) {
return;
}
var data = __assign({ pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() }, event);
var data = __assign(__assign({}, event), { pid: this.projectID, pg: this.activePage, lc: getLocale(), tz: getTimezone(), ref: getReferrer(), so: getUTMSource(), me: getUTMMedium(), ca: getUTMCampaign() });
this.sendRequest('custom', data);
};
Lib.prototype.trackPageViews = function (options) {
@ -127,14 +127,12 @@
return this.pageData.actions;
}
this.pageViewsOptions = options;
var hbInterval, interval;
var interval;
if (!(options === null || options === void 0 ? void 0 : options.unique)) {
interval = setInterval(this.trackPathChange, 2000);
}
if (!(options === null || options === void 0 ? void 0 : options.noHeartbeat)) {
setTimeout(this.heartbeat, 3000);
hbInterval = setInterval(this.heartbeat, 28000);
}
setTimeout(this.heartbeat, 3000);
var hbInterval = setInterval(this.heartbeat, 28000);
var path = getPath({
hash: options === null || options === void 0 ? void 0 : options.hash,
search: options === null || options === void 0 ? void 0 : options.search,
@ -163,23 +161,17 @@
this.perfStatsCollected = true;
return {
// Network
// @ts-ignore
dns: perf.domainLookupEnd - perf.domainLookupStart,
// @ts-ignore
tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0,
// @ts-ignore
conn: perf.secureConnectionStart ? perf.secureConnectionStart - perf.connectStart : perf.connectEnd - perf.connectStart,
// @ts-ignore
response: perf.responseEnd - perf.responseStart,
dns: perf.domainLookupEnd - perf.domainLookupStart, // DNS Resolution
tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0, // TLS Setup; checking if secureConnectionStart is not 0 (it's 0 for non-https websites)
conn: perf.secureConnectionStart
? perf.secureConnectionStart - perf.connectStart
: perf.connectEnd - perf.connectStart, // Connection time
response: perf.responseEnd - perf.responseStart, // Response Time (Download)
// Frontend
// @ts-ignore
render: perf.domComplete - perf.domContentLoadedEventEnd,
// @ts-ignore
dom_load: perf.domContentLoadedEventEnd - perf.responseEnd,
// @ts-ignore
page_load: perf.loadEventStart,
render: perf.domComplete - perf.domContentLoadedEventEnd, // Browser rendering the HTML time
dom_load: perf.domContentLoadedEventEnd - perf.responseEnd, // DOM loading timing
page_load: perf.loadEventStart, // Page load time
// Backend
// @ts-ignore
ttfb: perf.responseStart - perf.requestStart,
};
};
@ -193,20 +185,6 @@
};
this.sendRequest('hb', data);
};
Lib.prototype.checkIgnore = function (path) {
var _a;
var ignore = (_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.ignore;
if (Array.isArray(ignore)) {
for (var i = 0; i < ignore.length; ++i) {
if (ignore[i] === path)
return true;
// @ts-ignore
if (ignore[i] instanceof RegExp && ignore[i].test(path))
return true;
}
}
return false;
};
// Tracking path changes. If path changes -> calling this.trackPage method
Lib.prototype.trackPathChange = function () {
var _a, _b;
@ -222,15 +200,10 @@
}
};
Lib.prototype.getPreviousPage = function () {
var _a, _b;
// Assuming that this function is called in trackPage and this.activePage is not overwritten by new value yet
// That method of getting previous page works for SPA websites
if (this.activePage) {
var shouldIgnore = this.checkIgnore(this.activePage);
if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise)) {
return null;
}
return shouldIgnore ? null : this.activePage;
return this.activePage;
}
// Checking if URL is supported by the browser (for example, IE11 does not support it)
if (typeof URL === 'function') {
@ -246,76 +219,60 @@
if (host !== refHost) {
return null;
}
var shouldIgnore = this.checkIgnore(pathname);
if (shouldIgnore && ((_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.doNotAnonymise)) {
return null;
}
return shouldIgnore ? null : pathname;
return pathname;
}
catch (_c) {
catch (_a) {
return null;
}
}
return null;
};
Lib.prototype.trackPage = function (pg, unique) {
var _a, _b;
if (unique === void 0) { unique = false; }
if (!this.pageData)
return;
this.pageData.path = pg;
var shouldIgnore = this.checkIgnore(pg);
if (shouldIgnore && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.doNotAnonymise))
return;
var perf = this.getPerformanceStats();
var prev;
if (!((_b = this.pageViewsOptions) === null || _b === void 0 ? void 0 : _b.noUserFlow)) {
prev = this.getPreviousPage();
}
var prev = this.getPreviousPage();
this.activePage = pg;
this.submitPageView(shouldIgnore ? null : pg, prev, unique, perf);
this.submitPageView(pg, prev, unique, perf, true);
};
Lib.prototype.submitPageView = function (pg, prev, unique, perf) {
var data = {
Lib.prototype.submitPageView = function (pg, prev, unique, perf, evokeCallback) {
var _a;
var privateData = {
pid: this.projectID,
perf: perf,
unique: unique,
};
var pvPayload = {
lc: getLocale(),
tz: getTimezone(),
ref: getReferrer(),
so: getUTMSource(),
me: getUTMMedium(),
ca: getUTMCampaign(),
unique: unique,
pg: pg,
perf: perf,
prev: prev,
};
this.sendRequest('', data);
};
Lib.prototype.debug = function (message) {
var _a;
if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.debug) {
console.log('[Swetrix]', message);
if (evokeCallback && ((_a = this.pageViewsOptions) === null || _a === void 0 ? void 0 : _a.callback)) {
var callbackResult = this.pageViewsOptions.callback(pvPayload);
if (callbackResult === false) {
return;
}
if (callbackResult && typeof callbackResult === 'object') {
Object.assign(pvPayload, callbackResult);
}
}
Object.assign(pvPayload, privateData);
this.sendRequest('', pvPayload);
};
Lib.prototype.canTrack = function () {
var _a, _b, _c, _d;
if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled) {
this.debug('Tracking disabled: the \'disabled\' setting is set to true.');
return false;
}
if (!isInBrowser()) {
this.debug('Tracking disabled: script does not run in browser environment.');
return false;
}
if (((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') {
this.debug('Tracking disabled: respecting user\'s \'Do Not Track\' preference.');
return false;
}
if (!((_d = this.options) === null || _d === void 0 ? void 0 : _d.debug) && isLocalhost()) {
return false;
}
if (isAutomated()) {
this.debug('Tracking disabled: navigation is automated by WebDriver.');
if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.disabled) ||
!isInBrowser() ||
(((_b = this.options) === null || _b === void 0 ? void 0 : _b.respectDNT) && ((_c = window.navigator) === null || _c === void 0 ? void 0 : _c.doNotTrack) === '1') ||
(!((_d = this.options) === null || _d === void 0 ? void 0 : _d.devMode) && isLocalhost()) ||
isAutomated()) {
return false;
}
return true;

View File

@ -34,11 +34,11 @@
},
"homepage": "https://swetrix.com/docs",
"dependencies": {
"@types/node": "^20.8.6",
"@types/node": "^20.11.8",
"tslib": "^2.6.2"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^25.0.5",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"rimraf": "^4.4.1",
"rollup": "^2.79.1",
@ -46,6 +46,6 @@
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-typescript2": "^0.36.0",
"rollup-plugin-uglify": "^6.0.4",
"typescript": "^5.2.2"
"typescript": "^5.3.3"
}
}

View File

@ -1,13 +1,21 @@
import {
isInBrowser, isLocalhost, isAutomated, getLocale, getTimezone, getReferrer,
getUTMCampaign, getUTMMedium, getUTMSource, getPath,
isInBrowser,
isLocalhost,
isAutomated,
getLocale,
getTimezone,
getReferrer,
getUTMCampaign,
getUTMMedium,
getUTMSource,
getPath,
} from './utils'
export interface LibOptions {
/**
* When set to `true`, all tracking logs will be printed to console and localhost events will be sent to server.
* When set to `true`, localhost events will be sent to server.
*/
debug?: boolean
devMode?: boolean
/**
* When set to `true`, the tracking library won't send any data to server.
@ -37,6 +45,29 @@ export interface TrackEventOptions {
}
}
// Partial user-editable pageview payload
export interface IPageViewPayload {
lc: string | undefined
tz: string | undefined
ref: string | undefined
so: string | undefined
me: string | undefined
ca: string | undefined
pg: string
prev: string | null | undefined
}
interface IPerfPayload {
dns: number
tls: number
conn: number
response: number
render: number
dom_load: number
page_load: number
ttfb: number
}
/**
* The object returned by `trackPageViews()`, used to stop tracking pages.
*/
@ -60,21 +91,9 @@ export interface PageViewsOptions {
*/
unique?: boolean
/** A list of Regular Expressions or string pathes to ignore. */
ignore?: Array<string | RegExp>
/** 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. */
doNotAnonymise?: boolean
/** Do not send Heartbeat requests to the server. */
noHeartbeat?: boolean
/** Send Heartbeat requests when the website tab is not active in the browser. */
heartbeatOnBackground?: boolean
/** Disable user-flow */
noUserFlow?: boolean
/**
* Set to `true` to enable hash-based routing.
* For example if you have pages like /#/path or want to track pages like /path#hash
@ -86,6 +105,14 @@ export interface PageViewsOptions {
* For example if you have pages like /path?search
*/
search?: boolean
/**
* Callback to edit / prevent sending pageviews.
*
* @param payload - The pageview payload.
* @returns The edited payload or `false` to prevent sending the pageview. If `true` is returned, the payload will be sent as-is.
*/
callback?: (payload: IPageViewPayload) => IPageViewPayload | boolean
}
export const defaultPageActions = {
@ -111,6 +138,7 @@ export class Lib {
}
const data = {
...event,
pid: this.projectID,
pg: this.activePage,
lc: getLocale(),
@ -119,7 +147,6 @@ export class Lib {
so: getUTMSource(),
me: getUTMMedium(),
ca: getUTMCampaign(),
...event,
}
this.sendRequest('custom', data)
}
@ -134,15 +161,14 @@ export class Lib {
}
this.pageViewsOptions = options
let hbInterval: NodeJS.Timeout, interval: NodeJS.Timeout
let interval: NodeJS.Timeout
if (!options?.unique) {
interval = setInterval(this.trackPathChange, 2000)
}
if (!options?.noHeartbeat) {
setTimeout(this.heartbeat, 3000)
hbInterval = setInterval(this.heartbeat, 28000)
}
setTimeout(this.heartbeat, 3000)
const hbInterval = setInterval(this.heartbeat, 28000)
const path = getPath({
hash: options?.hash,
@ -163,12 +189,12 @@ export class Lib {
return this.pageData.actions
}
getPerformanceStats(): object {
getPerformanceStats(): IPerfPayload | {} {
if (!this.canTrack() || this.perfStatsCollected || !window.performance?.getEntriesByType) {
return {}
}
const perf = window.performance.getEntriesByType('navigation')[0]
const perf = window.performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming
if (!perf) {
return {}
@ -178,25 +204,19 @@ export class Lib {
return {
// Network
// @ts-ignore
dns: perf.domainLookupEnd - perf.domainLookupStart, // DNS Resolution
// @ts-ignore
tls: perf.secureConnectionStart ? perf.requestStart - perf.secureConnectionStart : 0, // TLS Setup; checking if secureConnectionStart is not 0 (it's 0 for non-https websites)
// @ts-ignore
conn: perf.secureConnectionStart ? perf.secureConnectionStart - perf.connectStart : perf.connectEnd - perf.connectStart, // Connection time
// @ts-ignore
conn: perf.secureConnectionStart
? perf.secureConnectionStart - perf.connectStart
: perf.connectEnd - perf.connectStart, // Connection time
response: perf.responseEnd - perf.responseStart, // Response Time (Download)
// Frontend
// @ts-ignore
render: perf.domComplete - perf.domContentLoadedEventEnd, // Browser rendering the HTML time
// @ts-ignore
dom_load: perf.domContentLoadedEventEnd - perf.responseEnd, // DOM loading timing
// @ts-ignore
page_load: perf.loadEventStart, // Page load time
// Backend
// @ts-ignore
ttfb: perf.responseStart - perf.requestStart,
}
}
@ -213,19 +233,6 @@ export class Lib {
this.sendRequest('hb', data)
}
private checkIgnore(path: string): boolean {
const ignore = this.pageViewsOptions?.ignore
if (Array.isArray(ignore)) {
for (let i = 0; i < ignore.length; ++i) {
if (ignore[i] === path) return true
// @ts-ignore
if (ignore[i] instanceof RegExp && ignore[i].test(path)) return true
}
}
return false
}
// Tracking path changes. If path changes -> calling this.trackPage method
private trackPathChange(): void {
if (!this.pageData) return
@ -244,13 +251,7 @@ export class Lib {
// Assuming that this function is called in trackPage and this.activePage is not overwritten by new value yet
// That method of getting previous page works for SPA websites
if (this.activePage) {
const shouldIgnore = this.checkIgnore(this.activePage)
if (shouldIgnore && this.pageViewsOptions?.doNotAnonymise) {
return null
}
return shouldIgnore ? null : this.activePage
return this.activePage
}
// Checking if URL is supported by the browser (for example, IE11 does not support it)
@ -272,13 +273,7 @@ export class Lib {
return null
}
const shouldIgnore = this.checkIgnore(pathname)
if (shouldIgnore && this.pageViewsOptions?.doNotAnonymise) {
return null
}
return shouldIgnore ? null : pathname
return pathname
} catch {
return null
}
@ -291,68 +286,62 @@ export class Lib {
if (!this.pageData) return
this.pageData.path = pg
const shouldIgnore = this.checkIgnore(pg)
if (shouldIgnore && this.pageViewsOptions?.doNotAnonymise) return
const perf = this.getPerformanceStats()
let prev
if (!this.pageViewsOptions?.noUserFlow) {
prev = this.getPreviousPage()
}
const prev = this.getPreviousPage()
this.activePage = pg
this.submitPageView(shouldIgnore ? null : pg, prev, unique, perf)
this.submitPageView(pg, prev, unique, perf, true)
}
submitPageView(pg: null | string, prev: string | null | undefined, unique: boolean, perf: any): void {
const data = {
submitPageView(
pg: string,
prev: string | null | undefined,
unique: boolean,
perf: IPerfPayload | {},
evokeCallback?: boolean,
): void {
const privateData = {
pid: this.projectID,
perf,
unique,
}
const pvPayload = {
lc: getLocale(),
tz: getTimezone(),
ref: getReferrer(),
so: getUTMSource(),
me: getUTMMedium(),
ca: getUTMCampaign(),
unique,
pg,
perf,
prev,
}
this.sendRequest('', data)
}
if (evokeCallback && this.pageViewsOptions?.callback) {
const callbackResult = this.pageViewsOptions.callback(pvPayload)
private debug(message: string): void {
if (this.options?.debug) {
console.log('[Swetrix]', message)
if (callbackResult === false) {
return
}
if (callbackResult && typeof callbackResult === 'object') {
Object.assign(pvPayload, callbackResult)
}
}
Object.assign(pvPayload, privateData)
this.sendRequest('', pvPayload)
}
private canTrack(): boolean {
if (this.options?.disabled) {
this.debug('Tracking disabled: the \'disabled\' setting is set to true.')
return false
}
if (!isInBrowser()) {
this.debug('Tracking disabled: script does not run in browser environment.')
return false
}
if (this.options?.respectDNT && window.navigator?.doNotTrack === '1') {
this.debug('Tracking disabled: respecting user\'s \'Do Not Track\' preference.')
return false
}
if (!this.options?.debug && isLocalhost()) {
return false
}
if (isAutomated()) {
this.debug('Tracking disabled: navigation is automated by WebDriver.')
if (
this.options?.disabled ||
!isInBrowser() ||
(this.options?.respectDNT && window.navigator?.doNotTrack === '1') ||
(!this.options?.devMode && isLocalhost()) ||
isAutomated()
) {
return false
}

View File

@ -1,6 +1,4 @@
import {
Lib, LibOptions, TrackEventOptions, PageViewsOptions, PageActions, defaultPageActions,
} from './Lib'
import { Lib, LibOptions, TrackEventOptions, PageViewsOptions, PageActions, defaultPageActions } from './Lib'
export let LIB_INSTANCE: Lib | null = null
@ -62,7 +60,7 @@ export function trackViews(options?: PageViewsOptions): Promise<PageActions> {
/**
* This function is used to manually track a page view event.
* It's useful if your application uses esoteric routing which is not supported by Swetrix by default.
*
*
* @param path Path of the page to track (this will be sent to the Swetrix API and displayed in the dashboard).
* @param prev Path of the previous page.
* @param unique If set to `true`, only 1 event with the same ID will be saved per user session.