Table of Contents
- Setting up
- Feature
- Init Tracker
- Cross subdomain and domain
- Logger
- Set UserId
- Reset UserId
- Set referrer
- Set channel
- Set terminal
- Scroll depth
- Latency Tracking
- PageView
- Link Tracking
- Custom Event
- Form tracking
- HeartBeat
- Search Event
- Cart Event
- Checkout Event
- Payment Event
- Alert Event
- Error Event
- Scan Event
- Exception Event
- Addition Param Table
- Content Tracking
- Guide for Single Page App
- Technology
Setting up
To use tracker.js in an async manner, first add the following script into your website template’s
<script type="text/javascript">
!function(a,d,e,g,b,h,c,f){a[b]||(a.GlobalTrackerNamespace=a.GlobalTrackerNamespace||[],a.GlobalTrackerNamespace.push(b),a.GlobalTrackerNamespace.push(h),a[b]=function(){(a[b].q=a[b].q||[]).push(arguments)},a[b].q=a[b].q||[],(c=d.createElement(e)).async=!0,c.src=g,(f=d.getElementsByTagName(e)[0]).parentNode.insertBefore(c,f),window.onerror=function(c,e,f,g,d){return a[b]("exception",{msg:c,error:d}),!1},window.onunhandledrejection=function(c){return a[b]("exception",{msg:c.reason,error:"unhandledrejection"}),!1})}(window,document,"script","https://cdn.tekoapis.com/tracker/dist/v2/tracker.full.min.js","track","https://tracking.tekoapis.com")
track("init", {$APP_ID})
</script>
In your tracking code,
- {$APP_ID} would be replaced by the idsite of the website you are tracking in Tracking.
This code might look a bit strange to those of you familiar with JavaScript, but that is because it is made to run asynchronously. In other words, browsers will not wait for the tracker.js file to be downloaded in order to show your page.
For asynchronous tracking, configuration and tracking calls are pushed onto the global track function for execution, independent of the asynchronous loading of tracker.js. The format is:
track("API_method_name", parameter);
For example:
track("setCurrentUrl", "https://github.com/teko-vn/tracker-js");
Feature
Init Tracker *
Tracker initialization is indicated with the "init" string and takes two arguments:
track("init", "123", { userId: 1 });
- “123” - AppId
- userId - this userId of App (options)
Cross subdomain and domain *
Tracker can create visitor and visit cross of domain and subdomain throw:
track("useSubDomain", true);
Logger
Tracker allow to access body of request before marshal to base64:
track("hookMessage", (body) => {
// do somethings...
});
SetUserId Single Page App
track("setUserId", <= userId =>)
Reset userId when logout
When logout using "resetUserId" to clear userId:\
track("resetUserId")
Set referrer manual
track('setReferrerUrl', currentUrl);
Set channel
track('setChannel', <channelName>);
Set terminal
track('setTerminal', <terminalName>);
Scroll depth
App will check percentage of scroll depth when user scroll on page
track("enableScrollDepth", options?)
options = {
percentInterval: "10", // ceiling percentage default = 1
trackDelay: "500" // throttle when user scroling
}
This will implement to funtion document.onScroll to check user activity after document apply css
Latency Tracking
App can measure network latency to monitor performance and connectivity
Manual Latency Measurement
Measure latency once to a specific URL:
track("measureLatency", options?)
options = {
url: "https://api.example.com/health", // optional, defaults to current domain health endpoint
method: "HEAD", // "GET" or "HEAD" (default: "GET")
timeoutMs: 5000 // optional, default: 5000ms
}
Automatic Latency Measurement
Enable automatic latency measurement with custom interval:
track("enableLatencyAuto", options?)
options = {
url: "https://api.example.com/health", // optional, defaults to current domain health endpoint
method: "HEAD", // "GET" or "HEAD" (default: "GET")
intervalMs: 30000, // custom interval in milliseconds (default: 180000ms = 3 minutes, minimum: 10000ms = 10 seconds)
timeoutMs: 5000 // request timeout in milliseconds (default: 5000ms)
}
Latency Event Details
Latency measurements are sent as TimingEvent with the following properties:
- category: “network”
- variable: “latency”
- label: HTTP method used (“GET” or “HEAD”)
- duration: Round-trip time in milliseconds
- attr1: URL that was measured
The latency tracking uses modern fetch API with AbortController for timeouts, and falls back to XMLHttpRequest for older browsers.
PageView
With server rendering
Page views are tracked using the "enablePageView" method. This is generally part of the first Tracker tag to fire on a particular web page:
track("enablePageView")
This will implement to funtion onload and onbeforeunload to check user activity
With client rendering
Plugins:
Create React App:
- https://git.teko.vn/_data/tracking/react-tracker-teko
- https://www.npmjs.com/package/react-tracker-teko
Vue:
Next:
Note Parameter *:
- host: “https://tracking.tekoapis.com”
- urlServeJsFile: “https://cdn.tekoapis.com/tracker/dist/v2/tracker.full.min.js"
Link Tracking
Auto detect
Turn on link click tracking like this:
track("enableLinkClick", filterProps) // filterProps is optional
Tracker will auto triger on a tag to detect user click.
filterOption use className filter like Form. Check here to know How to filter a Tag
Manual
AdditionsField follows table: AdditionParamTable. Field in addtionsField can be undefined!
You can use function like this:
track("linkClick", nameOfAction || null ,{
elementId: string;
elementClasses: string[];
elementTarget: string;
targetUrl: string;
text: string;
})
Custom Event
Schema Custom Event
| Field | Required | Description | Type |
|---|---|---|---|
| action | no | this is action | string |
| category | no | this is category | string |
| label | no | this is label | string |
| property | no | this is property | string |
| value | no | this is value | number |
track("customEvent", "countGoal" , {
action: "payment",
category: "food",
value: 100,
});
Form tracking
Tracker automatic form tracking detects three event types:
-
change_form: use
enableChangeFormWhen a user changes the value of a textarea, input, or select element inside a form, a
change_formevent will be fired. It will capture the name, type, and new value of the element, and the id of the parent form. -
focus_form: use
enableFocusFormWhen a user focuses on a form element, a
focus_formevent will be fired. It will capture the id and classes of the form and the name, type, and value of the textarea, input, or select element inside the form that received focus. -
submit_form: use
enableSubmitFormWhen a user submits a form, a
submit_formevent will be fired. It will capture the id and classes of the form and the name, type, and value of all textarea, input, and select elements inside the form.
Note: with lazy submit form, Auto submit form will be not detected! Should add element form with cmd:
// main.js
track("init", ....)
track("enableFormTracking");
Manual
// form.js
btn.addEventListener("click", () => {
const form = document.getElementById("myForm");
track("manualSubmitForm", form);
});
Auto
// main.js
track("enableFocusForm");
track("enableChangeForm");
track("enableSubmitForm");
Configuration Filter Form
It may be that you do not want to track every field in a form, or every form on a page. You can customize form tracking by passing a configuration argument to the enableFormTracking method. This argument should be an object with two elements named “forms” and “fields”. The “forms” element determines which forms will be tracked; the “fields” element determines which fields inside the tracked forms will be tracked. As with link click tracking, there are three ways to configure each field: a blacklist, a whitelist, or a filter function. You do not have to use the same method for both fields.
- Blacklists
This is an array of strings used to prevent certain elements from being tracked. Any form with a CSS class in the array will be ignored. Any field whose name property is in the array will be ignored. All other elements will be tracked.
- Whitelists
This is an array of strings used to turn on certail. Any form with a CSS class in the array will be tracked. Any field in a tracked form whose name property is in the array will be tracked. All other elements will be ignored.
- Filter functions
This is a function used to determine which elements are tracked. The element is passed as the argument to the function and is tracked if and only if the value returned by the function is truthy.
Form Tag will filter by CSS className attribute
Input Tag will filter by CSS name attribute
For exampletrack("enableFormTracking", {
fields: {
blacklist: ["password"],
whilelist: ["username"],
filter: (input) => {
return elt.id !== "private";
}
},
forms: {
blacklist: ["payment"],
whilelist: ["login"],
filter: (formElement) => {
return true
}
},
});
HeartBeat
Page pings are enabled by:
track("enableHeartBeat", timeAfterLastActive(s), timeInterval(s))
For example
track("enableHeartBeat", 15, 10)
The first ping would occur after 15 seconds, and subsequent pings every 10 seconds as long as the user continued to browse the page actively. Up to table content
Search Event
Use the siteSearch method to track users searching your website. Here are its signature:
track("siteSearch", {
keywords: string;
params: string;
order?: string;
sort?: string;
})
For example
track("siteSearch", {
keywords: "core i7",
params: "laptop"
})
Cart Event
These methods let you track users adding, removing items, increasing quantity or decrease quantity from a cart on an ecommerce site
| Field | Required? | Description | Type |
|---|---|---|---|
| skuId | true | SKU of product | string |
| skuName | true | Name of product | string |
| price | true | price of product | number |
| promotionPrice | true | PromotionPrice of product | number |
| quantity | true | Quantity added, removed, increase, decrease from cart | number |
| coupon | false | Coupon of items | string |
| promotionId | false | promotionId | string |
| status | true | State can “success” or “failed” or “timeout” | string |
| orderId | false | Id of order | string |
| cartId | false | Id of cart | string |
There are some methods below:
- addToCart
- removeFromCart
- selectProduct
- unselectProduct
- increaseQuantityProduct
- decreaseQuantityProduct
- revertProductToCart For example
AdditionsField follows table: AdditionParamTable. Field in addtionsField can be undefined!
track(
"addToCart",
{
sku: "123",
name: "core i7",
price: 11000000,
promotionPrice: 10000000,
quantity: 1,
status: "success"
},
{
utmSource: 'facebook'
}
)
Checkout Event
Modelled on Google Analytics ecommerce tracking capability, Tracker uses three methods that have to be used together to track online transactions:
- Create a transaction object. Use
setOrdermethod to initialize a transaction object. This will be the object that is loaded with all the data relevant to the specific transaction that is being tracked including all the items in the order, the prices of the items, the price of shipping and theorderId. - Add items to the transaction. Use the
addProductmethod to add data about each individual item to the transaction object. - Submit the transaction to Tracker using the
trackCheckoutOrdermethod, once all the relevant data has been loaded into the object.
setOrder
The setOrder method creates a transaction object. It takes 7 possible parameters, two of which are required:
| Field | Required? | Description | Type |
|---|---|---|---|
| orderId | true | Internal unique order id number for this transaction | string |
| amountAfterDiscount | true | Grand Total revenue of the transaction (including tax, shipping, etc.) | number |
| amountBeforeDiscount | true | Sub total amount, typically the sum of items prices for all items in this order (before Tax and Shipping costs are applied) | number |
| tax | false | Tax amount for this order | number |
| discountAmount | false | Total discount price | number |
| shippingFee | false | Shipping amount for this order | number |
| shippingPartner | false | Shipping partner in this order | string |
| shippingAddressCode | false | Code của Phường/Xã | string |
| shippingProvince | false | Province of Address shipping | string |
| shippingDistrict | false | District of Address shipping | string |
| shippingWard | false | Ward of Address shipping | string |
| shippingStreet | false | Street of Address shipping | string |
| shippingAddress | false | Full Address shipping | string |
| paymentMethod | true | Method of payment (“Cash, JCB, Visa, MasterCard, InternetBanking, EWallet, VnpayQR, PaymentGW”) | string |
| paymentBank | false | Bank of payment | string |
| status | true | State can be “success”, “failed”, “timeout” | string |
| note | false | some Note | string |
For example
track("setOrder", {
orderId: "123",
amountAfterDiscount: 1500000,
amountBeforeDiscount: 1500000,
paymentMethod: 'COD',
status: 'success'
});
addProduct
The addProduct method is used to capture the details of each product item included in the transaction. It should therefore be called once for each item:
| Field | Required? | Description | Type |
|---|---|---|---|
| skuId | true | SKU of product | string |
| skuName | true | Name of product | string |
| price | true | price of product | number |
| promotionPrice | true | PromotionPrice of product | number |
| quantity | true | Quantity added, removed, increase, decrease from cart | number |
For example
track("addProduct", {
skuId: "7126127js71223",
skuName: "Bàn phím Fuhlen",
price: 750000,
promotionPrice: 750000,
quantity: 1,
});
clearCart
track("clearCart");
trackCheckoutOrder
Once the transaction object has been created (using setOrder) and the relevant item data added to it using the addProduct method, we are ready to send the data to the collector. This is initiated using the trackCheckoutOrder method or destroy transaction :
AdditionsField follows table: AdditionParamTable. Field in addtionsField can be undefined!
track("trackCheckoutOrder", {
utmSource: 'facebook'
});
Addition Param Table
| Field | Required? | Type |
|---|---|---|
| utmSource | false | string |
| utmTerm | false | string |
| utmCampaign | false | string |
| utmContent | false | string |
| utmMedium | false | string |
| utmAgent | false | string |
| attr1 | false | string |
| attr2 | false | string |
| attr3 | false | string |
| attr4 | false | string |
| attr5 | false | string |
Put it together
<html>
<head>
<title>Receipt for your PC purchase from Phong Vu product</title>
<script type="text/javascript">
track("setOrder", {
orderId: "123",
...
});
track("addProduct", {
skuId: "7126127js71223",
skuName: "Bàn phím Fuhlen",
price: 750000,
promotionPrice: 750000,
quantity: 1,
...
});
track("trackCheckoutOrder");
</script>
</head>
<body>
Thank you for your order. You will receive an email containing all your order details.
</body>
</html>
Payment Event
Event for Payment Flow, attributes are described below:
| Field | Required? | Description | Type |
|---|---|---|---|
| orderId | true | Id of order | string |
| referral | true | deeplink trên app hoặc url trên web | string |
| amount | false | Amount for this order | number |
| partnerTransactionId | false | Mã giao dịch thanh toán của đối tác trả về | string |
| paymentMethod | true | Phương thức thanh toán | string |
| paymentBank | false | Ngân hàng thanh toán | string |
| status | true | State can be “success”, “failed”, “timeout” | string |
| statusCode | false | Respons lỗi trả về từ OM, errorCode từ firebase đối với VNPAY | number |
AdditionsField follows table: AdditionParamTable. Field in addtionsField can be undefined!
track("payment", {
orderId: 'abcxyz',
....
},
{ utmSource: 'facebook' });
Alert Event
Event for User Alert, attributes are described below:
| Field | Required? | Description | Type |
|---|---|---|---|
| alertType | true | Type of Alert | string |
| alertMessage | true | Message of alert | string |
track("alert", {
alertType: "abcxyz",
alertMessage: "this is message of error"
});
Error Event
Event for All Error, attributes are described below:
| Field | Required? | Description | Type |
|---|---|---|---|
| errorSource | true | Tất cả các lỗi http và websocket client nhận được đều phải bắn lên tracking server! | string |
| apiCall | true | url of the appi call that return error | string |
| apiPayload | true | payload that was sent with API call | string |
| httpResponseCode | false | kể cả các trường hợp HttpResponse 500, 503 đều phải gửi lên tracker hết! Thậm chí nếu lỗi mất kết nối đến server cũng phải gửi lên tracker | string |
| responseJson | false | responseJson | string |
| errorCode | true | mã Error code được gửi ở trong api call response json | string |
| errorMessage | true | Tên Error message được gửi ở trong api call response json | string |
track("error", {
errorSource: 'abcxyz',
....
});
Scan Event
Attributes are described below:
| Field | Required? | Description | Type |
|---|---|---|---|
| scanId | false | ID cuả QR / Bar code được scan | string |
| regionName | false | QR / Bar code được scan ở vùng nào | string |
| target | false | Địa chỉ đích đến của hành động scan | string |
| payload | false | payload client chủ động gửi kèm sự kiện scan | string |
track("scan", {
scanId: 'abcxyz',
....
});
Exception Event
Tracker-js can auto collect all unhandleerror event by event-name: exception
Can see this event on kibana
Content Tracking
Command
| Tracker | Props |
|---|---|
| “enableTrackAllContentImpressions” | not required |
| “enableTrackVisibleContentImpressions” | not required |
| “enableTrackInteractionContentWithInNode” | not required |
| “enableTrackContentImpressionsWithInNode” | not required |
| “manualTrackVisibleContentImpressions” | IPropsVisibleContentEvent |
| “manualTrackInteractionContent” | IPropsInteractionContentEvent |
Track only visible content impressions within a page
Enable to track only visible content impressions via trackVisibleContentImpressions(checkOnScroll, timeIntervalInMs). With visible we mean the content block has been in the view port and is not hidden (opacity, visibility, display, …).
-
Optionally you can tell us to not rescan the DOM after each scroll by passing checkOnScroll=false. Otherwise, we will check whether the previously hidden content blocks became visible meanwhile after a scroll and if so track the impression.
- Limitation: If a content block is placed within a scrollable element (overflow: scroll), we do currently not detect when such an element becomes visible.
-
Optionally you can tell us to rescan the entire DOM for new content impressions every X milliseconds by passing timeIntervalInMs=500. By default, we will rescan the DOM every 750ms. To disable it pass timeIntervalInMs=0.
- Rescanning the entire DOM and detecting the visible state of content blocks can take a while depending on the browser, hardware and amount of content.
Both checkOnScroll and timeIntervalInMs cannot be changed after this method was called the first time.
track("enableTrackVisibleContentImpressions", checkOnScroll: boolean = false, intervalInMs: number = 750)
Props Manual
interface IPropsInteractionContentEvent {
interaction: string;
regionName: string;
contentName: string;
target: string;
payload: string;
}
interface IPropsVisibleContentEvent {
regionName: string;
contentName: string;
index: number;
}
Example
track("manualTrackVisibleContentImpressions", {
regionName: "string";
contentName: "string";
index: 0;
})
track("manualTrackInteractionContent", {
interaction: "click",
contentName: "name",
regionName: "region",
target: "target",
payload: "payload",
})
Tagging content
| Attribute | Description |
|---|---|
| [data-track-content] | Defines a content block |
| [data-content-region-name=”"] | Defines the name of the region block |
| [data-content-name=”"] | Defines the name of the content block |
| [data-content-index=”"] | Defines the content index |
| [data-content-target=”"] | Defines the content target |
| [data-content-payload=”"] | Defines the content payload |
| [data-content-ignoreinteraction] | Declares to not automatically track the interaction |
Example
JS code
track("enableTrackVisibleContentImpressions", true);
HTML code
<div class="searchTrends">
<div>TÌM KIẾM PHỔ BIẾN</div>
<div>
<div
data-track-content
data-content-region-name="popularKeyword"
data-content-name="sku2"
data-content-index="0"
data-content-target="/abc/mamamy"
data-content-payload="it must be string"
>
mamamy
</div>
<div
data-track-content
data-content-region-name="popularKeyword"
data-content-name="sku1"
data-content-index="1"
data-content-target="/abc/bobby"
data-content-payload="it must be string"
>
bobby
</div>
</div>
</div>
Guide for Single Page App
Recomment using some plugin for Vue, React, Angular
For Vue: https://www.npmjs.com/package/vue-tracker-teko
For React: https://www.npmjs.com/package/react-tracker-teko
For Angular: Not support
Techs
Tracker-js uses a number of open source projects to work properly:
- [Lodash] - A modern JavaScript utility library delivering modularity, performance & extra
- [TypeScript] - Language to build javascript