npm package: @schibsted/niche-tracking
Description: Package containing tracking logic reused between multiple Schibsted niche sites
Latest version: 4.12.4

# Niche Tracking

## Description

This repository contains code we use for tracking. The goal of niche-tracking is to be used in all of our products. Currently it's used by [tek-web](https://schibsted.ghe.com/niche-and-services/tek-web), [godt-web](https://schibsted.ghe.com/niche-and-services/godt2-web) and [pent-web](https://schibsted.ghe.com/niche-and-services/pent2-web).

## Local development

Nothing fancy here. First install dependencies
clone repository, open terminal and run.

```bash
npm i
```

Next start transpiling the source code:

```bash
npm run transpile:watch
```

### Linking

Note: order of command execution is important.

In order to make your project available as package locally:

```bash
npm link
```

And in project you need:

```bash
npm link @schibsted/niche-tracking
```

And now you are all good. Your project will now use the local version of niche-tracking instead of the one in node_modules.

### Unlinking

After you end working on the package you need to unlink it.

First, in the project where the package was used:

```bash
npm unlink --no-save @schibsted/niche-tracking
```

Second, in the niche-tracking package:

```bash
npm unlink
```

## Supported trackers

Currently pulse and mbl trackers are implemented.

## How to use it and how it works

Package exports `Tracker` class and all implemented tracker objects. You can import it like this:

```javascript
import { Tracker, pulse, mbl } from '@schibsted/niche-tracking';
```

Next you need to create tracker instance with proper parameters

```javascript
const tracker = new Tracker({
    pageViewTrackerMappers,
    eventTrackerMappers,
    pageLeaveTrackerMappers,
    enabled,
    trackers: [pulse, mbl],
});
```

When you have the tracker instance you will have to initialize it with proper config. Calling this method will download all tracking scripts and actually make them work. Don't worry, you can call
`tracker.pageView` and `tracker.event` methods before calling `tracker.initialize` as all build in trackers have event queue that will be unloaded after initialization.

`tracker.initialize` methods takes config with tracker specific options. You can see them here:

- [pulse](./src/pulse/README.md)
- [mbl](./src/mbl/README.md)

Let's discuss Tracker constructor parameters

### trackers

Array with trackers you want to use.
You can import those from package or provide your own. They must be objects with three methods:

- pageView
- event
- initialize
- [navigationEvent](#navigationevent) (optional)
- addPageLeaveTracking
- trackActivePageLeave

### pageViewTrackerMappers, eventTrackerMappers, pageLeaveTrackerMappers

These are objects with following format:

```javascript
{
    [TYPE]: {
        [TRACKERNAME]: optionTransormFunction
    }
}
```

### enabled

This flag lets you disable the tracking. Please keep in mind that even if you set `enabled: false` mappers will still be called to keep the behaviour as close to production as it can be.

Where `TYPE` is unique name of event type you want to track (defined by you), `TRACKERNAME` is (who would have guessed?) tracker name and `optionTransformFunction` is function that transforms data from `option` object to data that specific tracker needs for that event.

For example it could look like this:

```javascript
const pageViewTrackerMappers = {
    [SCREENS.SECTION]: {
        pulse: (options) => ({
            object: {
                name: window.document.title,
                id: options.category,
                type: 'Listing',
                category: options.category,
                filters: {
                    query: options.location.search,
                },
            },
        }),
        mbl: (options) => ({
            url: window.location.toString(),
            title: window.document.title,
            image: options.image.url,
            referrer: document.referrer,
        }),
    },
};
```

Remember out tracker instance? Just to remind you:

```javascript
const tracker = new Tracker({
    pageViewTrackerMappers,
    eventTrackerMappers,
    pageLeaveTrackerMappers,
    enabled,
    trackers: [pulse, mbl],
});
```

Now each time you call `tracker.pageView(SCREENS.SECTION, options)` the tracker will create:

- pulseSpecificOptions,
- mblSpecificOptions

according to transform functions you provided in `pageViewTrackerMappers`.

Next it will call `pulse.pagewiew(pulseSpecificOptions)`, `mbl.pagewiew(mblSpecificOptions)`.

As you can see it enables you to implement most of the tracking in declarative way. All you need is choose which trackers you need and provide proper options mapping.

As a recommendation I suggest providing redux state as options and using selectors in option transorm function.

## Experiments

Experiments is a field used for A/B tests tracking. It should be passed during `tracker` initalization and contain list of all A/B tests that user is part of.
For example it could look like this:

```javascript
const tracker = new Tracker({
    pageViewTrackerMappers,
    eventTrackerMappers,
    enabled,
    trackers: [pulse],
});
const experiments = [
    {
        id: 'experimentId', // unique identifier of A/B test
        variant: 'variant-b', // identifier of a variant which will be served to user
    },
    {
        id: 'anotherExperimentId',
        variant: 'another-variant-a',
    },
];
tracker.initalize({
    ...trackersConfig,
    clientId,
    experiments,
});
```

In the case of the `pulse` tracker, this list will be added to every page view and engagement event.

## NavigationEvent

**NOTE:**

> Use this method for **internal navigation** only.
>
> It can fire only **ONE** (latest) `navigationEvent` per `pageView` invocation.

What this method does is:

- it creates an event like it would normally do,
- **postpones sending this event** until next `pageView` invocation,
- once `pageView` is invoked the pending event will have `tracker` property value set to whatever the `object` property of current `pageView` event is.

In short: it will remove necessity of manual creation of `target` property of an event in case of internal navigation.

## Deployment

Deployment is done using [Travis CI](https://travis.schibsted.io/niche-and-services/niche-tracking)

The new version of the package is deployed by Travis after you push a semver tag (e.g. `v1.0.1` to Github).
The make the process as smooth as possible we're using [release-it](https://www.npmjs.com/package/release-it) package.

To make the release work you need to do the following:

1. Generate a Github personal token with `repo` credentials.
2. Set the token as `GITHUB_TOKEN` environment variable.
3. Run `npm run release` and follow the wizard there (mostly pick the patch/minor/major release type and confirm everything else).

Release-it does the following:

- makes sure you have your workspace clean and `GITHUB_TOKEN` set
- bumps the version in `package.json` and `package-lock.json`
- commits the changes
- tags the commit with the version number
- pushes the changes and tag
- creates a Github Release with the changelog since the last release

## Polyfills

This package requires only one polyfill: Promise.

## Useful links

To get more general idea of how tracking works check our [team docs](https://pages.schibsted.ghe.com/niche-and-services/team/tracking)