@firstfleet/ffwebanalytics

Simply analytics library for web and hybrid apps

Usage no npm install needed!

<script type="module">
  import firstfleetFfwebanalytics from 'https://cdn.skypack.dev/@firstfleet/ffwebanalytics';
</script>

README

@firstfleet/ffwebanalytics

Requirements


This library uses and relies on the navigator.beacon web api. Browsers or environments that do not support this web api will not be able to use this library, and the library will throw an exception when trying to send the analytics payload.

To read more about the Beacon web api, please see the documentation. Beacon Api

Description


ffwebanalytics is a npm package used for creating and tracking simple click based analytics in a website, or hybrid mobile app. It uses a combination of data attributes, and the beacon api to track and send analytic events to an endpoint of your choice.

When a click event is detected, it checks the element clicked, and if there is no matching data attribute, will traverse the dom tree upwards looking for it. This means that even if you click on a child element inside the element you want to track, it will still fire the analytics event correctly.

Installation


npm install @firstfleet/ffwebanalytics --save

Configuration


The minimum configuration needed for the analytics engine is a property called postUrl.

However, there are other options you can pass into the configuration object.

The complete configuration object looks like

const config = {
    postUrl: 'https://urltopostto.com',
    dataTag: 'data-analtyic',
    appName: 'app-name',
    autoStart: true,
    staticData: {userid: 'userid', appId: 'appName'}
};

postUrl - This is the url you want the data to be posted to. The data will be a json blob.

dataTag - This is the data attribute you want the analytics engine to watch for, it defaults to data-analytic, but can be whatever you want.

appName - The name of the application. This will be included with the dataTag in the meta section of the analytics data payload. This is so you can identify which app is sending the data.

autoStart - weather to auto run the listener for click events. Defaults to true, but if you want this can be set to false, and you can manually start the listener by using the startAnalyticsListener method.

staticData - This is static data you want sent along with every analytics event. Great for sending in a userId, or appName with every analytics event. You only need to pass this in the config, if you are leaving autoStart set to true. You can also modify the static data by setting the analytics engine staticData property, even after the listener, as been started.

What is a data tag?

So, the data tag is an html attribute to associate data with a particular element.

For more info please see The Docs.

Methods


startAnalyticsListener - this method will start the analytics listener, and it will begin listening for click events on the document, and looking for data tags that match the dataTag passed into the config, or 'data-analytic' if you left the default. This method can also take in an override parameter for the on click event method. If you want to write your own click event handler. The default handler should work though, but this allows you to extend the functionality if needed.

stopAnalyticsListener - this will stop the analytics listener.

addStaticDataProperty - adds a property to the static data object, with a value.

removeStaticDataProperty - removes a property from the static data object, along with the value.

addMetaProperty - adds a property with a value to the meta section of the payload.

removeMetaProperty - removes a property and the value from the meta section of the payload.

Usage


In this first example. I am going to set autoStart to false, meaning I do not have to pass in a staticData object. I am going to leave the data tag to the default value of data-analytic.

Once I instantiate the engine, I am going to set the staticData property, and then start the listener.

<!-- Set the default dataTag on a clickable html element -->
<div onclick="readArticle" data-analytic="click_read_article"></div>
 // Import the engine
 import {AnalyticsEngine} from "@firstfleet/ffwebanalytics";

 // Create the config
 const analyticsConfig = {
     postUrl: 'https://postdatahere.com/analytics',
     appName: 'Burbun',
     autoStart: fasle
 };
 
 // Instantiate the engine
 const analytics = new AnalyticsEngine(analyticsConfig);
 
 // Set the static data property with data
 analytics.staticData = {userId: 'username'}

 // Start the listner
 analytics.startAnalyticsListener();

You can also just set everything in the config, and then let it start the listener on instantiation. autoStart defaults to true, so that is the only property I will not pass in. I also will override the data attribute I want the engine to look for.

<div onclick="destroyWorld" data-track="destroy_world"></div>
// Import the engine
import {AnalyticsEngine} from "@firstfleet/ffwebanalytics";

// Create the config
const analyticsConfig = {
    postUrl: 'https://postdatahere.com/analytics',
    dataTag: 'data-track', 
    appName: 'CombatWombat',
    staticData: {userId: 'username'}
};

// Instantiate the engine
const analytics = new AnalyticsEngine(analyticsConfig);

A more advanced example

<div onclick="bigRedButton" data-track="should_not_have_touched_that"></div>
// Import the engine
import {AnalyticsEngine} from "@firstfleet/ffwebanalytics";

// Create the config
const analyticsConfig = {
    postUrl: 'https://postdatahere.com/analytics',
    dataTag: 'data-track', 
    appName: 'NotYourMommasWebsite',
    autoStart: false,
};

// Instantiate the engine
const analytics = new AnalyticsEngine(analyticsConfig);

// Set the static data object
analytics.staticData = {userId: 'userName'};

// Get the users favorite flavor of ice cream
const usersFavoriteIceCream = getUserFlavor(userId);

// Add it to the staticData
analytics.addStaticDataProperty('flavor', usersFavoriteIceCream);

// Start the listener
analytics.startAnalyticsListener();

// Remove the flavor property from static data
analytics.removeStaticDataProperty('flavor');
// Stop the listner
setTimeout(() => {
    analytics.stopAnalyticsListener();
}, 10000);

Parsing the data


To parse the data in nodejs for example, you will need to parse out the text/plain blob from the request body.

const express = require("express");
const bodyParser = require("body-parser");
const app = express();

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));

// parse application/json
app.use(bodyParser.json());

//serving the static content inside our public folder
app.use(express.static('public'));

app.post("/analytics", (req, res) => {
    
    // Parse the text/plain body to JSON
    const body = JSON.parse(req.body);
    
    // Here is your analytics data
    console.log(body);
    
    res.sendStatus(204);
});
app.listen(8081, () => console.log("Listening on 8081"))

The analytics payload will look like this (below), after you parse it into json. There is a meta property that contains a unix time stamp, and the data attribute that the listener was watching for.

Then you have the data attribute value pulled off the event target, and after that will be any staticData variables defined in the config, or set on the object.

{
  "meta": {
    "timestamp": "1633720745707",
    "dataTag": "data-track",
    "appName": "OneAppToRuleThemAll"
  },
  "event": "should_not_have_touched",
  "staticData": {
    "userId": "username"
  }
}

FirstFleet Specific Documentation


Everything below only applies to FirstFleet Incs internal use. Anyone is welcome to use this library, and we have attempted to keep it as agnostic as possible.

FirstFleet Specific Static Data


This library can be used by anyone, but firstfleet specifically supports these fields to be passed in the staticData object.

Any extra data passed in, won't be mapped until the internal endpoint, and DB has been updated to support it.

All these properties are optional, as denoted in the docs, you can pass in as many, or as few as you want.

/**
 * @type {Object} staticData
 * @property {string} [userId]
 * @property {string} [locationId]
 * @property {number} [latitude]
 * @property {number} [longitude]
 * @property {string} [tractor]
 * @property {string} [trailer]
 * @property {number} [odometer]
 * @property {string} [tabletSerial]
 * @property {string} [orderNumber]
 * @property {string} [stopNumber]
 * @property {string} [moveNumber]
 */

FirstFleet Data Attribute Value Structure


We parse the data attribute value using a pipe delimited string. This is so we can store the event type, as well as the event value.

So, you would structure the value assigned to the data attribute used for analytics as follows.

<div data-analytic="click_button|Login"></div>

Then, in the DB, click_button would be stored as the eventType, and Login would be stored as the event. This makes analyzing the data much easier from a reporting context.

You can pass in only an eventType by leaving out the |

<div data-analytic="click_button"></div>

You will still get the eventType, but the event will be NULL in the DB.

FirstFleet Authorization


To see how to authorize the post request, please see the internal documentation.