@gitlab/application-sdk-browser
Version:
Client side Browser SDK for GitLab Application services
260 lines (230 loc) • 6.49 kB
text/typescript
import {
newTracker,
enableActivityTracking,
trackSelfDescribingEvent,
trackPageView,
setUserId,
addGlobalContexts,
disableAnonymousTracking,
BrowserTracker,
PageViewEvent,
CommonEventProperties,
setCustomUrl as _setCustomUrl,
setReferrerUrl as _setReferrerUrl,
setDocumentTitle as _setDocumentTitle,
} from '@snowplow/browser-tracker';
import {
enableLinkClickTracking,
refreshLinkClickTracking as _refreshLinkClickTracking,
} from '@snowplow/browser-plugin-link-click-tracking';
import {
enableErrorTracking,
trackError as _trackError,
} from '@snowplow/browser-plugin-error-tracking';
import { isEmpty } from './utils/isEmpty';
import { doNotTrackEnabled } from './utils/doNotTrack';
import {
SCHEMAS,
DEFAULT_TRACKER_ID,
DEFAULT_PAGEPING_OPTIONS,
} from './utils/constants';
import { getSnowplowOptions } from './utils/getSnowplowOptions';
import {
AllowedPlugins,
GitLabClientSDKOptions,
ErrorEventProperties,
GitLabClientSDKType,
} from './types';
export function glClientSDK(
options: GitLabClientSDKOptions
): GitLabClientSDKType {
return new GitLabClientSDK(options);
}
class GitLabClientSDK {
snowplow: BrowserTracker | null = null;
options: GitLabClientSDKOptions = {
appId: '',
host: '',
hasCookieConsent: false,
trackerId: DEFAULT_TRACKER_ID,
pagePingTracking: true,
};
defaultPlugins: AllowedPlugins = {
clientHints: true,
linkTracking: true,
performanceTiming: true,
errorTracking: true,
};
constructor(options: GitLabClientSDKOptions) {
this.options = { ...this.options, ...options };
this.options.plugins = {
...this.defaultPlugins,
...(options?.plugins ?? {}),
};
if (!this.trackingEnabled) return;
const {
appId,
host,
hasCookieConsent = false,
trackerId = DEFAULT_TRACKER_ID,
pagePingTracking,
plugins,
} = this.options;
if (!appId) {
console.warn('GitLab: No appId was provided');
return;
}
if (!host) {
console.warn('GitLab: No host was provided');
return;
}
/**
* Initialize Snowplow Client with options
*/
const snowplowOptions = getSnowplowOptions(
appId,
hasCookieConsent,
plugins
);
this.snowplow = newTracker(trackerId, host, snowplowOptions) || null;
if (typeof pagePingTracking === 'boolean' && pagePingTracking) {
// Enables page activity tracking (sends page pings to the Collector regularly) with default options.
enableActivityTracking(DEFAULT_PAGEPING_OPTIONS);
} else if (typeof pagePingTracking === 'object') {
// Override default settings
enableActivityTracking({
minimumVisitLength:
pagePingTracking.minimumVisitLength ??
DEFAULT_PAGEPING_OPTIONS.minimumVisitLength,
heartbeatDelay:
pagePingTracking.heartbeatDelay ??
DEFAULT_PAGEPING_OPTIONS.heartbeatDelay,
});
}
/** enable required plugins */
const { linkTracking, errorTracking } = plugins;
if (linkTracking) {
enableLinkClickTracking();
}
if (errorTracking) {
enableErrorTracking();
}
}
private get trackingEnabled(): boolean {
return !doNotTrackEnabled();
}
/**
* Track the user defined custom event
*
* @param {eventName} eventName - Name of the custom event
* @param {eventAttributes} eventAttributes - Additional information for custom event
* @returns {void}
*/
public track(
eventName: string,
{ ...eventAttributes }: Record<string, any> = ({} = {})
): void {
if (!this.trackingEnabled) return;
trackSelfDescribingEvent({
event: {
schema: SCHEMAS.CUSTOM_EVENT,
data: {
name: eventName,
props: { ...eventAttributes },
},
},
});
}
/**
* enableLinkClickTracking only tracks clicks on links which exist when the page has loaded.
* If new links can be added to the page after then which you wish to track,
* just use refreshLinkClickTracking.
*/
public refreshLinkClickTracking = _refreshLinkClickTracking.bind(this);
/**
* Send error as self-describing event
*
* @param errorAttributes - The event information
* @returns {void}
*/
public trackError({
...errorAttributes
}: ErrorEventProperties & CommonEventProperties): void {
if (!this.trackingEnabled) return;
// if error tracking plugin is not enabled, do not capture the error
if (!this.options.plugins?.errorTracking) {
console.warn('GitLab: Error tracking plugin is not enabled');
return;
}
_trackError({ ...errorAttributes });
}
/**
* Set cookie consent
*/
addCookieConsent() {
disableAnonymousTracking({
stateStorageStrategy: 'cookieAndLocalStorage',
});
}
/**
* Tracks the page views
*
* @param {event} event - The page view event.
* @returns {void}
*/
public page(event?: PageViewEvent & CommonEventProperties): void {
if (!this.trackingEnabled) return;
trackPageView(event);
}
/**
* Set the business defined userId and other user attributes
*
* @param {userId} userId - The business-defined user ID
* @param {userAttributes} userAttributes - The business-defined user attributes
* @returns {void}
*/
public identify(
userId: string,
userAttributes: Record<string, any> = ({} = {})
): void {
if (!this.trackingEnabled) return;
setUserId(userId);
if (!isEmpty(userAttributes)) {
let userContext = {
schema: SCHEMAS.USER_CONTEXT,
data: userAttributes,
};
addGlobalContexts([userContext]);
}
}
/**
* Sets a custom URL for the current page view event.
*
* @param {string} url - The custom URL to set.
* @returns {void}
*/
public setCustomUrl(url: string): void {
if (!this.trackingEnabled) return;
_setCustomUrl(url);
}
/**
* Sets a referrer URL for the current page view event.
*
* @param {string} url - The referrer URL to set.
* @returns {void}
*/
public setReferrerUrl(url: string): void {
if (!this.trackingEnabled) return;
_setReferrerUrl(url);
}
/**
* Sets a Document title which will be used as override
*
* @param {string} url - The referrer URL to set.
* @returns {void}
*/
public setDocumentTitle(title: string): void {
if (!this.trackingEnabled) return;
_setDocumentTitle(title);
}
}