@swissfederalrailways/internet-tracking
v15.0.6
Published
A build and test tool for JS tracking code at SBB
Downloads
94
Readme
sbb-internet-tracking
Declarative and imperative library that implements the SBB Tracking Guide.
Install
The Library is hosted under the internal SBB Artifactory. To install it from this registry you need to have the following registry configured in your npm config: https://www.npmjs.com/package/@swissfederalrailways/internet-tracking
We are currently moving the library to bintray.com. Updated version
npm install @swissfederalrailways/internet-tracking
Module Format
The module is in UMD format and can therefore be imported in multiple ways:
var tracking = require('@swissfederalrailways/internet-tracking');
<script src="../path/to/@swissfederalrailways/internet-tracking/dist/main.js"></script>
With the global script import, the library will then load itself into window.sbbInternetTracking
Usage
Initialization
The Library can track clicks and impressions by inspecting HTML attributes automatically. We use data-sit-*
attributes for this.
All clicks are tracked automatically. To initialize the click and impression tracking you have to call the following after your HTML Elements are ready:
sbbInternetTracking.scanForElementsToTrack();
Furthermore, you can call this method whenever there are new elements coming to the DOM that should now be tracked.
The first event that should be tracked is when the page is loaded.
// fire on every pageload
sbbInternetTracking.dataLayerApi.pageLoaded({
pageInstanceID: '571882',
destinationURI: '/freizeit-ferien/reisen-schweiz/regionen/vier-jahreszeiten-im-wallis',
pageName: 'Vier Jahreszeiten im Wallis',
language: 'de',
primaryCategory: 'sbb.ch',
// all the following values are optional
sysEnv: 'production',
pageID: '1234',
// If the page is an error page
errorCode: '404',
errorMessage: 'This page does not exist.',
user: {
loginType: 'SwissPass B2C',
loginStatus: 1,
language: 'fr', // This is the user language, not the current language of the website
}
})
To signal that the page is ready for the user and the tracking of the data layer should start, the following method can be called as soon as the page load data is ready:
sbbInternetTracking.dataLayerApi.dataLayerReady();
If the page changes without a reload the two events "Page Load" and then "Data Layer Ready" have to be dispatched again.
General Click Tracking
Generally all clicks on or inside Elements with an href
attribute are tracked. To give more details for specific links the following attributes can be used:
If you have a navigation click that should be tracked, but is not on an Element with an href
attribute you can use the data-sit-href
attribute.
When using this attribute you should only pass absolute URLs since this won't get automatically resolved by the browser.
<a href="...">I am tracked</a>
<div data-sit-href="...">
<span>I am tracked as well</span>
</div>
When tracking clicks, the clicked element and the parent elements are sent to the analytics, which allows more detailed analysis of what specific items the user clicks. This is done via the dom-component-path library: https://code-ext.sbb.ch/projects/WCMS/repos/sbb-internet-tracking-dom-component-path. The identifieres of these elements are derived from the most specific attribute we can find which is either:
data-sit-component
Attribute- ID
- Class
- HTML Tag
Enhanced Click Tracking
If some relevant HTML Node in the tree is not specific enough, we can add a data-sit-component="component name"
to it.
This allows for more details in later analysis and also position information when there are siblings of the same element.
If you need additional information to this click you can add an data-sit-primary-category
or data-sit-action
attribute to your link.
<a
href="..."
data-sit-action="my action"
data-sit-primary-category="my category"
>I am tracked with additional information</a>
If you want to pass in additional information which should be stored on the top level of an event (not inside the composedPath), you can
utilize data-sit-location
. If the element that is clicked does not have this attribute set, the library searches the DOM hierarchy until it finds a value - if any.
<div data-sit-location="footer">
Every click inside me has the location attribute
</div>
In case you need another property that behaves like data-sit-location, there is data-sit-variant
, which behaves in exactly the same way.
<div data-sit-variant="departure">
Every click inside me has the variant attribute
</div>
Similarly, there is data-sit-detail
, which behaves in exactly the same way.
<div data-sit-detail="detail">
Every click inside me has the detail attribute
</div>
Search
Search Page Initialization
Tracking the appearance of the search result page can be done two ways, depending on when you have the data available.
If the data is ready upon pageload you can pass the according values on the pageLoaded
call:
sbbInternetTracking.dataLayerApi.pageLoaded({
// default pageLoaded parameters (see above)
// ...
// search parameters
search: {
level: 'primary', // 'primary' |'secondary'
value: 'search term',
results: 42,
}
});
When you don't have the data ready on pageload you can pass it later on using the searchLoaded
function. Be aware that this function has to be called before calling the "dataLayerReady" method.
sbbInternetTracking.dataLayerApi.searchLoaded({
value: 'search term',
results: 42,
level: 'primary',
});
It is also possible to add this payload in the markup of your page, the "dataLayerReady" method will then pick it up and push it to the data layer before dispatching the event.
<div
data-sit-search-loaded="{\"value\": \"search term\", \"results\": 42, \"level\": \"primary\"}"
>...</div>
Search Result Click
Search results on the result page need to be annotated like this:
<!-- Search Result (only on search result page - for search suggestion dropdown see below) -->
<a
href="..."
data-sit-search-result
data-sit-search-value="Search query"
data-sit-search-result-level="primary" <!-- "primary" | "secondary" -->
data-sit-search-result-label="Result label"
data-sit-search-result-position="5" <!-- indexing starts with 0 -->
data-sit-search-result-page="2" <!-- indexing starts with 0 -->
>...</a>
Search Dropdown Click
Clicks on an item suggested by the dropdown of the search box are tracked manually by using the following code:
sbbInternetTracking.dataLayerApi.trackSearchResultNavigation({
destination: 'absolute/destination/of/link',
component: clickedElement,
label: 'Label of clicked element',
value: 'Search term',
type: 'autosuggest',
level: 'primary', // 'primary' | 'secondary'
position: 2, // 0 indexed
callback: () => window.location.href = '/wherever',
})
The type indicates hereby if the click occured on a suggested search or on an item in the most searched list. The position describes the position of the item in the list. The two lists of autosuggest and most searched have their own indexes.
The callback parameter will be called as soon as the tracking request has been sent or at least after 300ms. Before redirecting you should therefore wait for the callback to be called.
In cases where a dropdown click does not lead to a new page being loaded, a custom event could be used instead. For example:
sbbInternetTracking.dataLayerApi.sendCustomEvent({
eventName: 'search result display',
primaryCategory: 'primary search',
value: "sbb",
resultPageNumber: 1,
results: 621
})
Teaser
Declarative Setup
Standard teasers can be declaratively tracked using the following attributes:
<a
href="..."
data-sit-teaser
data-sit-teaser-headline="Teaser Headline"
data-sit-teaser-label="Teaser Label" <!-- optional -->
>...</a>
Manual Triggered Setup
Special Teasers like Carousels should trigger manually when a Teaser becomes visible since our library can't reliably determine this.
To ensure that it is not tracked twice, the data-sit-teaser
has to be set to manual:
<a
href="..."
data-sit-teaser="manual"
data-sit-teaser-headline="Teaser Headline"
data-sit-teaser-label="Teaser Label" <!-- optional -->
>...</a>
After this, the dataLayerApi
allows you to tell the library when a teaser is visible for the customer and when it has gotten invisble:
// When becoming visible:
sbbInternetTracking.observeTeaserElement(element);
// When becoming invisible:
sbbInternetTracking.unobserveTeaserElement(element);
The library will ensure that each impression is fired only once when certain thresholds are met. When the element is removed from the DOM it will not be tracked anymore.
Impression
Impressions are a more general form of teasers and can therefore be used for more use cases. Impressions fire events as soon as they enter the viewport fully.
<div
data-sit-impression
data-sit-impression-type="Type"
data-sit-impression-label="Impression"
data-sit-impression-headline="Headline"
>
...
</div>
Similar to teasers, if the impression element is not present at the time of the page load, the library has to be informed when it can start looking for such elements:
// When becoming visible
sbbInternetTracking.observeImpressionElement(element)
// When becoming invisible
sbbInternetTracking.unobserveImpressionElement(element)
Further, it is also possible to manually add an impression event to the datalayer:
sbbInternetTracking.trackImpression({
type: 'type',
headline: 'headline',
component: { ... },
label: 'label'
})
Accordions
Accordions should be tagged as such by setting the attributes data-sit-component
on the accordion elements.
It's important that equivalent items are siblings. That way we can calculate their relation to each other.
<div>
<div data-sit-component="accordion item"><span>My item 1</span></div>
<div data-sit-component="accordion item"><span>My item 2</span></div>
<div data-sit-component="accordion item"><span>My item 3</span></div>
</div>
To track accordion actions simply call trackAccordionAction
on the dataLayerApi whenever an accordion item openes or closes.
sbbInternetTracking.dataLayerApi.trackAccordionAction({
action: 'open',
component: accordionElement,
headline: 'Accordion Title',
label: 'Element label',
})
Since accordion actions (open/close) are likely to be called on regular clicks on the accordion item, the tracking library will also track this generic "click" event, not just the one you tiggered manually in the code above. To prevent this we have to exclude the element that opens/closes the accordion from the global click tracking like so:
<div data-sit-component="accordion item">
<button data-sit-ignore-clicks>Open Accordion</button>
<div>My Content</div>
</div>
Downloads
Download links or buttons need to be set up like the following:
<!-- Download Link -->
<a
href="..."
data-sit-download
data-sit-download-label="Download Label"
data-sit-download-filename="Filename.extension"
>...</a>
<!-- Download Button -->
<button
data-sit-href="..."
data-sit-download
data-sit-download-label="Download Label"
data-sit-download-filename="Filename.extension"
>...</button>
Update Login Type
The Login Type of the current user can be changed at runtime by calling the updateUserLoginType
method on our dataLayerApi.
sbbInternetTracking.dataLayerApi.updateUserLoginType({ loginType: 'SwissPass B2C' });
Fine Tuning
Label Text
In the click tracking we search the DOM tree for a useful label. We already exclude elements with the following css attributes:
.ignored-attributes {
display: none;
visibility: hidden;
opacity: 0;
}
If you need to exclude other elements you can provide the class names by calling the function
sbbInternetTracking.ignoreTextOfElementsWith('classNames', 'to', 'ignore')
Or there is also the declarative way with the attribute data-sit-ignore-label
:
<span data-sit-ignore-label>
Ignored Text
</span>
If you need to overwrite contents like sensible user data you can use the data-sit-replace-label-with
attribute.
<span data-sit-replace-label-with="USER_DATA">
Sensible Data
</span>
Ignore clicks
The global click tracker will pick up any clicks on the page. Sometimes we want to prevent this behaviour for certain elements. To exclude elements from being tracked you can add the following property:
<div data-sit-ignore-clicks></div>
Custom Events
There might be situations where you would like to manually push events onto the datalayer. For this, we have the following method available on the dataLayerApi.
sbbInternetTracking.dataLayerApi.sendCustomEvent({
eventName: 'eventName',
primaryCategory: 'primaryCategory',
additional: 'additional',
additionalNested: {
nested: 'nested'
}
})
Contribute
Running Tests
# install dependencies
npm install
# run tests on save
npm run tdd
Test Driven Development
The Test Driven Development approach is split into 2 phases:
- Write (failing) tests for the new functionality.
- Adapt the code to fix the tests.
This Project is structured for this type of development.
You find all the tests in the /tests
folder.
When you run the following command, your file-system is watched, and every time you save a file, the tests are atomatically re-run:
npm run tdd
If you wish to dive deeper into the actual setup of the tests, start in the following file:
/karma.conf
BrowserStack
BrowserStack is a service that gives us the possibility to run the tests on various different devices.
You need to set the following environment variables in order to connect to the BrowserStack API:
BROWSERSTACK_USERNAME
BROWSERSTACK_KEY
The easiest way is to define these variables in the rc
file of you shell, e.g.
~/.zshrc
or ~/.bashrc
.
The BROWSER
environment variable defines what browser the tests are run on.
You can prefix the npm run
command with the environment variable as follows:
# run the test on all configured browsers
BROWSER=all npm run test
# run the tests on IE11 on BrowserStack
BROWSER=ie npm run test
# run the tests on your local Chrome Browser
npm run test
The browsers are defined under the customLaunchers
key in the karma.conf.js
file.
Code Conventions
This project follows the JavaScript Standard Style, which is enforced through
ESLint. The npm run build
task will fail if there are style errors in the
code, hence it is highly recommended to install and run an ESLint plugin in
your editor of choice.