npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@swissfederalrailways/internet-tracking

v15.0.6

Published

A build and test tool for JS tracking code at SBB

Downloads

122

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:

  1. Write (failing) tests for the new functionality.
  2. 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.