• Stars
    star
    254
  • Rank 160,264 (Top 4 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 9 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A light, fast and flexible javascript tracking library

keen-tracking.js

A JavaScript tracking library for Keen. Track events, user actions, clicks, pageviews, conversions and more!

Slack

Installation

Install this package from NPM Recommended

npm install keen-tracking --save

Public CDN

<script crossorigin src="https://cdn.jsdelivr.net/npm/keen-tracking@5/dist/keen-tracking.min.js"></script>

Project ID & API Keys

Login to Keen IO to create a project and grab the Project ID and Write Key from your project's Access page.

Getting started

The following examples demonstrate how to implement rock-solid web analytics, capturing pageviews, clicks, and form submissions with robust data models.

Full documentation is available here

Using React? Check out these setup guides:

Upgrading from an earlier version of keen-js? Read this.


Record an Event

import KeenTracking from 'keen-tracking';

const client = new KeenTracking({
  projectId: 'PROJECT_ID',
  writeKey: 'WRITE_KEY'
});

client
  .recordEvent('purchases', {
    item: 'Avocado',
    number_of_items: 10,
    user: {
      name: 'John Smith'
    }
  })
  .then((response) => {
    // handle successful responses
  })
  .catch(error => {
    // handle errors
  });

Automated Event Tracking

Automatically record pageviews, clicks, form_submissions and element_views events with robust data models:

<script>
  (function(name,path,ctx){ctx[name]=ctx[name]||{ready:function(fn){var h=document.getElementsByTagName('head')[0],s=document.createElement('script'),w=window,loaded;s.onload=s.onreadystatechange=function(){if((s.readyState&&!(/^c|loade/.test(s.readyState)))||loaded){return}s.onload=s.onreadystatechange=null;loaded=1;ctx[name].ready(fn)};s.async=1;s.src=path;h.parentNode.insertBefore(s,h)}}})
  ('KeenTracking', 'https://cdn.jsdelivr.net/npm/keen-tracking@5/dist/keen-tracking.min.js', this);

  KeenTracking.ready(function(){
    const client = new KeenTracking({
      projectId: 'YOUR_PROJECT_ID',
      writeKey: 'YOUR_WRITE_KEY'
    });
    client.initAutoTracking();
  });
</script>

Learn how to configure and customize this functionality here


Pageview Tracking

First, let's create a new client instance with your Project ID and Write Key, and use the .extendEvents() method to define a solid baseline data model that will be applied to every single event that is recorded. Consistent data models and property names make life much easier later on, when analyzing and managing several event streams. This setup also includes our data enrichment add-ons, which will populate additional information when an event is received on our end.

import KeenTracking from 'keen-tracking';

const client = new KeenTracking({
  projectId: 'PROJECT_ID',
  writeKey: 'WRITE_KEY'
});
const helpers = KeenTracking.helpers;
const utils = KeenTracking.utils;

const sessionCookie = utils.cookie('rename-this-example-cookie');
if (!sessionCookie.get('guest_id')) {
  sessionCookie.set('guest_id', helpers.getUniqueId());
}

// optional
client.extendEvents(() => {
  return {
    geo: {
      ip_address: '${keen.ip}',
      info: {
        /* Enriched data from the API will be saved here */
        /* https://keen.io/docs/api/?javascript#ip-to-geo-parser */
      }
    },
    page: {
      title: document.title,
      url: document.location.href,
      info: { /* Enriched */ }
    },
    referrer: {
      url: document.referrer,
      info: { /* Enriched */ }
    },
    tech: {
      browser: helpers.getBrowserProfile(),
      user_agent: '${keen.user_agent}',
      info: { /* Enriched */ }
    },
    time: helpers.getDatetimeIndex(),
    visitor: {
      guest_id: sessionCookie.get('guest_id')
      /* Include additional visitor info here */
    },
    keen: {
      addons: [
        {
          name: 'keen:ip_to_geo',
          input: {
            ip: 'geo.ip_address'
          },
          output : 'geo.info'
        },
        {
          name: 'keen:ua_parser',
          input: {
            ua_string: 'tech.user_agent'
          },
          output: 'tech.info'
        },
        {
          name: 'keen:url_parser',
          input: {
            url: 'page.url'
          },
          output: 'page.info'
        },
        {
          name: 'keen:referrer_parser',
          input: {
            referrer_url: 'referrer.url',
            page_url: 'page.url'
          },
          output: 'referrer.info'
        }
      ]
    }
  }
});

// record the event
client
  .recordEvent('pageviews', {
    // here you can add even more data
    // some_key: some_value
  })
  .then((response) => {
    // handle responses
  }).catch(error => {
    // handle errors
  });

Every event that is recorded will inherit this baseline data model. Additional properties defined in client.recordEvent() will be applied before the event is finally recorded.

What else can this SDK do?

App Frameworks:

Video Players:

Full documentation is available here


Click and Form Submit Tracking

Clicks and form submissions can be captured with .listenTo(). This example further extends the client instance defined previously, and activates a simple timer when the page the loaded. Once a click or submit event is captured, the timer's value will be recorded as visitor.time_on_page.

import KeenTracking from 'keen-tracking';

const client = new KeenTracking({
  projectId: 'PROJECT_ID',
  writeKey: 'WRITE_KEY'
});
const helpers = KeenTracking.helpers;
const timer = KeenTracking.utils.timer();
timer.start();

KeenTracking.listenTo({
  'click .nav a': (e) => {
    return client.recordEvent('click', {
      action: {
        intent: 'navigate',
        target_path: helpers.getDomNodePath(e.target)
      },
      visitor: {
        time_on_page: timer.value()
      }
    });
  },
  'submit form#signup': (e) => {
    return client.recordEvent('form-submit', {
      action: {
        intent: 'signup',
        target_path: helpers.getDomNodePath(e.target)
      },
      visitor: {
        email_address: document.getElementById('signup-email').value,
        time_on_page: timer.value()
      }
    });
  }
});

Click events (clicks) will record specific attributes from the clicked element or its ancestor elements and pass them via the element property in the event object data:

// event object
{
    // ...

    // specific to the clicks event type
    "element": {
      "action" : undefined,                 // [DIRECT]
      "class": "cta",                       // [DIRECT]
      "href": "https://keen.io/",     // [INHERITED]
      "id": "main-cta",                     // [INHERITED]
      "event_key": "learn-more-cta",        // [INHERITED] from the `data-event-key` attribute
      "method": "learn-more-link",          // [DIRECT]
      "node_name": "A",                     // [DIRECT]
      "selector": "body > div:eq(0) > div:eq(1) > div:eq(0) > a", // [DIRECT]
      "text": "Learn More",                 // [INHERITED]
      "title": "Learn More",                // [INHERITED]
      "type": undefined,                    // [DIRECT]
      "x_position": 191,                    // [DIRECT]
      "y_position": 970                     // [DIRECT]
  }
}

In the above list of collected properties for a click event, some properties are gathered from the nearest ancestor elements if they can't be found on the immediate source element of the event. These properties are shown with [INHERITED] above.

For example, a click on the word clicked! below:

  <a href='foo.html' data-event-key='click-me-cta'>
    <span id='contrived-example'>I want to be <strong class='enhance'>clicked!</strong></span>
  </a>

Would generate an event including a mixture of immediate attributes and attributes found by traversing up the DOM tree:

{
  // ...
  "id" : "contrived-example",
  "class" : "enhance",
  "text" : "clicked!",
  "href" : "foo.html",
  "node_name" : "STRONG",
  "event_key" : "click-me-cta",
}

Note: The event_key value (data-event-key attribute) is a more explicit keen-specific identifier that gives you an option outside of href, id, and class values to group or identify and query clicks in a meaningful way without potential ID/class collisions or dual-use naming schemes.

Want to get up and running faster? This can also be achieved in the browser with automated event tracking.


Track views of the HTML elements

Use Intersection Observer to track elements that have been seen by a user. In an example the CSS selector of the HTML elements is defined as .track-element-view. Use threshold to control the sensitivity of the Observer. Note: This feature works only on the browsers that support Intersection Observer.

import KeenTracking from 'keen-tracking';

const client = new KeenTracking({
  projectId: 'PROJECT_ID',
  writeKey: 'WRITE_KEY'
});
const helpers = KeenTracking.helpers;

if(typeof IntersectionObserver !== 'undefined'){
  const elementViewsOptions = {
    threshold: 1.0,
  }
  const elementViewsCallback = (events, observer) => {
    events.forEach(el => {
      if(el.isIntersecting){
        return client
          .recordEvent({
            event_collection: 'element_views',
            event: {
              element: helpers.getDomNodeProfile(el.target)
           }
          });
      }
    });
  }
  const observer = new IntersectionObserver(elementViewsCallback, elementViewsOptions);
  const target = document.querySelectorAll('.track-element-view');
  target.forEach(el => {
    observer.observe(el);
  });
}

Block Bots and Improve Device Recognition

Install mobile-detect.js to identify basic device types and block noisy bots and crawlers.

npm install mobile-detect --save

This example further extends the client instance defined above, inserting a new tech.device_type property with three possible values: 'desktop', 'mobile', and 'tablet'. If the user agent is determined to be a bot, it may be ideal to abort and avoid recording an event.

import MobileDetect from 'mobile-detect';

const md = new MobileDetect(window.navigator.userAgent);
if (md.is('bot')) {
  return false;
}

// extends client instance defined previously
client.extendEvents(() => {
  return {
    tech: {
      device_type: md.tablet() ? 'tablet' : md.mobile() ? 'mobile' : 'desktop'
    }
  };
});

Check out the many additional methods supported by mobile-detect.js to further enrich your data model.

This can also be used with automated event tracking.


Server-side Event Tracking

const KeenTracking = require('keen-tracking');

const client = new KeenTracking({
  projectId: 'PROJECT_ID',
  writeKey: 'WRITE_KEY'
});

// promise
client
  .recordEvent('purchases', {
    item: 'Avocado',
    number_of_items: 10,
    user: {
      name: 'John Promise'
    }
  })
  .then((response) => {
    // handle successful responses
  })
  .catch(error => {
    // handle errors
  });

// or callback
client
  .recordEvent('purchases', {
    item: 'Avocado',
    number_of_items: 10,
    user: {
      name: 'John Callback'
    }
  }, (error, response) => {
    if (error) {
      // handle errors
      return;
    }
    // handle responses
  });

Cancel request

const KeenTracking = require('keen-tracking');

const client = new KeenTracking({
    projectId: 'PROJECT_ID',
    writeKey: 'WRITE_KEY'
});

const query = client
  .recordEvent('purchases', {
    item: 'Avocado',
    number_of_items: 10,
    user: {
      name: 'John Promise'
    }
  })

// cancel
query.abort();

// handling response and cancel
query.then(res => {
    // response
}).catch((err) => {
    if (err === 'REQUEST_ABORTED') {
        // request canceled
    }
});

In browser environment make sure to attach AbortController polyfill to support browsers which do not have that feature. You can do it by adding this script on your website:

https://cdn.jsdelivr.net/npm/[email protected]/dist/umd-polyfill.min.js


Handling connection problems

When KeenTracking encounters connection problems, it will retry to send the data.

import KeenTracking from 'keen-tracking';

const client = new KeenTracking({
  projectId: 'PROJECT_ID',
  writeKey: 'WRITE_KEY',

  // customize the default values
  retry: {
    limit: 10, // how many times retry to record an event
    initialDelay: 200, // initial delay between consecutive calls.
    // Each next retry will be delayed by (2^retries_count * 100) milliseconds,
    retryOnResponseStatuses: [ // array of invalid http response statuses
      408,
      500,
      502,
      503,
      504
    ]
  }
});

Unique events

Save the event only once.

client
  .recordEvent({
    event_collection: 'unique_clicks',
    event: {
      some_key: 'some_value',
      // ...
    },
    unique: true, // check if the event is unique, before sending to API
    cache: {
      storage: 'indexeddb', // for persistence. Remove this property to use RAM
      hashingMethod: 'md5', // remove this property to store as a stringified json
      maxAge: 1000 * 60, // store the information about unique value for 60 seconds
    }
  })
  .then((response) => {
    console.log('ok', response);
  })
  .catch(someError => {
    console.log('error', someError);
  });

Request types

By default, we make requests using the Fetch API.

For UI interactions, consider using the BeaconAPI. It's the fastest non-invasive way to track user behaviour. Due to its nature, BeaconAPI runs requests in the background, with no possibility to handle errors. If you want to handle errors, you need to use the Fetch API.

// specify request types for all requests
const client = new KeenTracking({
  projectId: 'PROJECT_ID',
  writeKey: 'WRITE_KEY',
  requestType: 'fetch' // fetch, beaconAPI, img
});

// you can use different requestType for a single request
client
  .recordEvent({
    event_collection: 'clicks',
    event: {
      some_key: 'some_value',
      // ...
    },
    requestType: 'beaconAPI'
  });

Custom Host

You can set a custom domain for requests

const client = new KeenTracking({
  projectId: 'PROJECT_ID',
  writeKey: 'WRITE_KEY',
  host: 'somehost.com'
});

Recorded Event ID

A successful response from our API does not contain the ID of the newly created event. We are using Cassandra Database (NoSQL), so there are no joins. Store all necessary data in each event you record. Denormalization and duplication of data is a fact of life with Cassandra. Read more:


Tracking Opt-Out

It's easy to build tracking opt-out functionality. If opt-out is set to true no data is recorded.

You can set up opt-out by defining client instance

const client = new KeenTracking({
  projectId: 'PROJECT_ID',
  writeKey: 'WRITE_KEY',
  optOut: true
});

or by invoking client.setOptOut(true) method

client.setOptOut(true);

Note: The user can block tracking in the browser by doNotTrack setting. We can respect or overwrite this setting by defining client instance

const client = new KeenTracking({
  projectId: 'PROJECT_ID',
  writeKey: 'WRITE_KEY',
  respectDoNotTrack: true // it's false by default
});

Contributing

This is an open source project and we love involvement from the community! Hit us up with pull requests and issues.

Learn more about contributing to this project.


Support

Need a hand with something? Shoot us an email at [email protected]. We're always happy to help, or just hear what you're building! Here are a few other resources worth checking out:

More Repositories

1

dashboards

Responsive dashboard templates πŸ“Šβœ¨
HTML
11,022
star
2

explorer

Data Explorer by Keen - point-and-click interface for analyzing and visualizing event data.
TypeScript
746
star
3

keen-js

https://keen.io/ JavaScript SDKs. Track users and visualise the results. Demo http://keen.github.io/keen-dataviz.js/
580
star
4

common-web

Turn web user activity into a analyzable stream of JSON event data
JavaScript
493
star
5

pingpong

HTTP monitoring for developers. Richer analytics, greater flexibility.
CSS
334
star
6

keen-dataviz.js

Data Visualization Charting Library
JavaScript
222
star
7

cohorts

Cohort Builder by Keen IO
111
star
8

keen-cli

A command line interface for Keen IO
Ruby
53
star
9

data-modeling-guide

Data Modeling Guide
53
star
10

github-analytics

GitHub Analytics with Keen IO
JavaScript
43
star
11

keen-analysis.js

A light JavaScript client for Keen
JavaScript
39
star
12

dashboards-dot-community

This is a collaborative project to help community managers be better at recording the impact of their activities and communicating the results.
27
star
13

keen-botkit

Analytics for Botkit by Keen IO
JavaScript
26
star
14

radialflows

Radial flow (sunburst) data visualization
Ruby
26
star
15

keen-arduino

A SDK to send events to Keen IO from an Arduino Yun
C++
15
star
16

open-data-collectors

A set of Pushpop jobs that collect data for anyone to use
Ruby
15
star
17

dashboard-builder

An easy to use JavaScript dashboard builder for event tracking
JavaScript
15
star
18

community-team

a little bit about us
14
star
19

dashboard-starter-sinatra

Sinatra template app for creating a Keen IO dashboard
JavaScript
13
star
20

community-code-of-conduct

Keen IO Community Code of Conduct
13
star
21

keen-css

Keen IO CSS Framework
CSS
13
star
22

keen

Mono-repository for Front-End projects
TypeScript
12
star
23

keen-gem-example

A Sinatra app that uses the keen gem to publish events asynchronously
Ruby
10
star
24

slate_algolia

Easily index your Slate-powered docs in Algolia
Ruby
10
star
25

dashboard-creator

TypeScript
8
star
26

keen.github.io

A collection of tools for building on Keen
CSS
7
star
27

keen-react-charts

A React Component for Keen-Dataviz.js
JavaScript
6
star
28

ecommerce-analytics-guide

Keen IO E-Commerce Analytics Guide
HTML
6
star
29

learn

Event Data Class by Keen IO
JavaScript
6
star
30

theme-builder

A custom CSS theme builder for Keen-Dataviz.js
JavaScript
5
star
31

community_ideas

A hub for tracking all of the things we want to build for the community
5
star
32

keen-cc3200

An SDK to send events to Keen IO from a Ti cc3200 board.
C
5
star
33

discoveries-demo

JavaScript
4
star
34

net-keenio-perl

A Perl library for the Keen IO analytics API (under construction)
Perl
4
star
35

keen-play-error-reporter

Sentry exception reporter for play-based apps.
Scala
4
star
36

keen-core.js

Core functionality powering keen-tracking.js and keen-analysis.js; not intended for direct use.
JavaScript
3
star
37

devise_keen

Track user events in the devise gem with Keen IO.
Ruby
3
star
38

discovery-manager.js

JavaScript
3
star
39

amp

Keen-AMP integration
HTML
3
star
40

keen-dataviz-webpack-boilerplate

JavaScript
2
star
41

analytics-in-sixty-seconds

Fastest client.draw in the West
HTML
2
star
42

comapp

JavaScript
1
star
43

react-dashboards

JavaScript
1
star
44

keen-tracking-adwords-example

JavaScript
1
star
45

keen-dataviz-maps

1
star
46

keen-ez-etl

A tiny script for exporting events from one project, modifying them, and loading them into another
Ruby
1
star