A lightweight analytics abstraction library for tracking page views, custom events, & identify visitors.
Designed to work with any third-party analytics tool or your own backend.
Read the docs or view the live demo app
Companies frequently change analytics requirements based on evolving needs. This results in a lot of complexity, maintenance, & extra code when adding/removing analytic services to a site or application.
This library aims to solves that with a simple pluggable abstraction layer.
Driving philosophy:
To add or remove an analytics provider, adjust the plugins
you load into analytics
during initialization.
This module is distributed via npm, which is bundled with node and should be installed as one of your project's dependencies.
npm install analytics --save
Or as a script tag:
<script src="https://unpkg.com/analytics/dist/analytics.min.js"></script>
import Analytics from 'analytics'
import googleAnalytics from '@analytics/google-analytics'
import customerIo from '@analytics/customerio'
/* Initialize analytics */
const analytics = Analytics({
app: 'my-app-name',
version: 100,
plugins: [
googleAnalytics({
trackingId: 'UA-121991291',
}),
customerIo({
siteId: '123-xyz'
})
]
})
/* Track a page view */
analytics.page()
/* Track a custom event */
analytics.track('userPurchase', {
price: 20,
item: 'pink socks'
})
/* Identify a visitor */
analytics.identify('user-id-xyz', {
firstName: 'bill',
lastName: 'murray',
email: 'da-coolest@aol.com'
})
See Analytics Demo for a site example.
The core analytics
API is exposed once the library is initialized with configuration.
Typical usage:
page
, identify
, track
in your appAnalytics library configuration
After the library is initialized with config, the core API is exposed & ready for use in the application.
Arguments
object
- analytics core configstring
- Name of site / appstring
|number
- Version of your appboolean
- Should analytics run in debug modeArray
.<AnalyticsPlugin> - Array of analytics pluginsExample
import Analytics from 'analytics'
import pluginABC from 'analytics-plugin-abc'
import pluginXYZ from 'analytics-plugin-xyz'
// initialize analytics
const analytics = Analytics({
app: 'my-awesome-app',
plugins: [
pluginABC,
pluginXYZ
]
})
Identify a user. This will trigger identify
calls in any installed plugins and will set user data in localStorage
Arguments
String
- Unique ID of userObject
- Object of user traitsObject
- Options to pass to identify callFunction
- Callback function after identify completesExample
// Basic user id identify
analytics.identify('xyz-123')
// Identify with additional traits
analytics.identify('xyz-123', {
name: 'steve',
company: 'hello-clicky'
})
// Fire callback with 2nd or 3rd argument
analytics.identify('xyz-123', () => {
console.log('do this after identify')
})
// Disable sending user data to specific analytic tools
analytics.identify('xyz-123', {}, {
plugins: {
// disable sending this identify call to segment
segment: false
}
})
// Send user data to only to specific analytic tools
analytics.identify('xyz-123', {}, {
plugins: {
// disable this specific identify in all plugins except customerio
all: false,
customerio: true
}
})
Track an analytics event. This will trigger track
calls in any installed plugins
Arguments
String
- Event nameObject
- Event payloadObject
- Event optionsFunction
- Callback to fire after tracking completesExample
// Basic event tracking
analytics.track('buttonClicked')
// Event tracking with payload
analytics.track('itemPurchased', {
price: 11,
sku: '1234'
})
// Fire callback with 2nd or 3rd argument
analytics.track('newsletterSubscribed', () => {
console.log('do this after track')
})
// Disable sending this event to specific analytic tools
analytics.track('cartAbandoned', {
items: ['xyz', 'abc']
}, {
plugins: {
// disable track event for segment
segment: false
}
})
// Send event to only to specific analytic tools
analytics.track('customerIoOnlyEventExample', {
price: 11,
sku: '1234'
}, {
plugins: {
// disable this specific track call all plugins except customerio
all: false,
customerio: true
}
})
Trigger page view. This will trigger page
calls in any installed plugins
Arguments
Object
- Page tracking optionsFunction
- Callback to fire after page view call completesExample
// Basic page tracking
analytics.page()
// Page tracking with page data overrides
analytics.page({
url: 'https://google.com'
})
// Fire callback with 1st, 2nd or 3rd argument
analytics.page(() => {
console.log('do this after page')
})
// Disable sending this pageview to specific analytic tools
analytics.page({}, {
plugins: {
// disable page tracking event for segment
segment: false
}
})
// Send pageview to only to specific analytic tools
analytics.page({}, {
plugins: {
// disable this specific page in all plugins except customerio
all: false,
customerio: true
}
})
Get user data
Arguments
string
- dot.prop.path of user data. Example: 'traits.company.name'Example
// Get all user data
const userData = analytics.user()
// Get user id
const userId = analytics.user('userId')
// Get user company name
const companyName = analytics.user('traits.company.name')
Clear all information about the visitor & reset analytic state.
Arguments
Function
- Handler to run after resetExample
// Reset current visitor
analytics.reset()
Fire callback on analytics ready event
Arguments
Function
- function to trigger when all providers have loadedExample
analytics.ready((payload) => {
console.log('all plugins have loaded or were skipped', payload);
})
Attach an event handler function for analytics lifecycle events.
Arguments
String
- Name of event to listen toFunction
- function to fire on eventExample
// Fire function when 'track' calls happen
analytics.on('track', ({ payload }) => {
console.log('track call just happened. Do stuff')
})
// Remove listener before it is called
const removeListener = analytics.on('track', ({ payload }) => {
console.log('This will never get called')
})
// cleanup .on listener
removeListener()
Attach a handler function to an event and only trigger it once.
Arguments
String
- Name of event to listen toFunction
- function to fire on eventExample
// Fire function only once per 'track'
analytics.once('track', ({ payload }) => {
console.log('This is only triggered once when analytics.track() fires')
})
// Remove listener before it is called
const listener = analytics.once('track', ({ payload }) => {
console.log('This will never get called b/c listener() is called')
})
// cleanup .once listener before it fires
listener()
Get data about user, activity, or context. Access sub-keys of state with dot.prop
syntax.
Arguments
string
- dot.prop.path value of stateExample
// Get the current state of analytics
analytics.getState()
// Get a subpath of state
analytics.getState('context.offline')
Storage utilities for persisting data. These methods will allow you to save data in localStorage, cookies, or to the window.
Example
// Pull storage off analytics instance
const { storage } = analytics
// Get value
storage.getItem('storage_key')
// Set value
storage.setItem('storage_key', 'value')
// Remove value
storage.removeItem('storage_key')
Get value from storage
Arguments
String
- storage keyObject
- storage optionsExample
analytics.storage.getItem('storage_key')
Set storage value
Arguments
String
- storage keyObject
- storage optionsExample
analytics.storage.setItem('storage_key', 'value')
Remove storage value
Arguments
String
- storage keyObject
- storage optionsExample
analytics.storage.removeItem('storage_key')
Async Management methods for plugins.
This is also where custom methods are loaded into the instance.
Example
// Enable a plugin by namespace
analytics.plugins.enable('keenio')
// Disable a plugin by namespace
analytics.plugins.disable('google-analytics')
Enable analytics plugin
Arguments
string
|Array
.<string
> - name of plugins(s) to disableFunction
- callback after enable runsExample
analytics.plugins.enable('google-analytics').then(() => {
console.log('do stuff')
})
// Enable multiple plugins at once
analytics.plugins.enable(['google-analytics', 'segment']).then(() => {
console.log('do stuff')
})
Disable analytics plugin
Arguments
string
|Array
.<string
> - name of integration(s) to disableFunction
- callback after disable runsExample
analytics.plugins.disable('google').then(() => {
console.log('do stuff')
})
analytics.plugins.disable(['google', 'segment']).then(() => {
console.log('do stuff')
})
The analytics
library comes with a large variety of event listeners that can be used to fire custom functionality when a specific lifecycle event occurs.
These listeners can be fired using analytics.on
& analytics.once
const eventName = 'pageEnd'
analytics.on(eventName, ({ payload }) => {
console.log('payload', payload)
})
Below is a list of the current available events
Event | Description |
---|---|
bootstrap |
Fires when analytics library starts up. This is the first event fired. '.on/once' listeners are not allowed on bootstrap Plugins can attach logic to this event |
params |
Fires when analytics parses URL parameters |
campaign |
Fires if params contain "utm" parameters |
initializeStart |
Fires before 'initialize', allows for plugins to cancel loading of other plugins |
initialize |
Fires when analytics loads plugins |
initializeEnd |
Fires after initialize, allows for plugins to run logic after initialization methods run |
ready |
Fires when all analytic providers are fully loaded. This waits for 'initialize' and 'loaded' to return true |
resetStart |
Fires if analytic.reset() is called. Use this event to cancel reset based on a specific condition |
reset |
Fires if analytic.reset() is called. Use this event to run custom cleanup logic (if needed) |
resetEnd |
Fires after analytic.reset() is called. Use this event to run a callback after user data is reset |
pageStart |
Fires before 'page' events fire. This allows for dynamic page view cancellation based on current state of user or options passed in. |
page |
Core analytics hook for page views. If your plugin or integration tracks page views, this is the event to fire on. |
pageEnd |
Fires after all registered 'page' methods fire. |
pageAborted |
Fires if 'page' call is cancelled by a plugin |
trackStart |
Called before the 'track' events fires. This allows for dynamic page view cancellation based on current state of user or options passed in. |
track |
Core analytics hook for event tracking. If your plugin or integration tracks custom events, this is the event to fire on. |
trackEnd |
Fires after all registered 'track' events fire from plugins. |
trackAborted |
Fires if 'track' call is cancelled by a plugin |
identifyStart |
Called before the 'identify' events fires. This allows for dynamic page view cancellation based on current state of user or options passed in. |
identify |
Core analytics hook for user identification. If your plugin or integration identifies users or user traits, this is the event to fire on. |
identifyEnd |
Fires after all registered 'identify' events fire from plugins. |
identifyAborted |
Fires if 'track' call is cancelled by a plugin |
userIdChanged |
Fires when a user id is updated |
registerPlugins |
Fires when analytics is registering plugins |
enablePlugin |
Fires when 'analytics.plugins.enable()' is called |
disablePlugin |
Fires when 'analytics.plugins.disable()' is called |
online |
Fires when browser network goes online. This fires only when coming back online from an offline state. |
offline |
Fires when browser network goes offline. |
setItemStart |
Fires when analytics.storage.setItem is initialized. This event gives plugins the ability to intercept keys & values and alter them before they are persisted. |
setItem |
Fires when analytics.storage.setItem is called. This event gives plugins the ability to intercept keys & values and alter them before they are persisted. |
setItemEnd |
Fires when setItem storage is complete. |
setItemAborted |
Fires when setItem storage is cancelled by a plugin. |
removeItemStart |
Fires when analytics.storage.removeItem is initialized. This event gives plugins the ability to intercept removeItem calls and abort / alter them. |
removeItem |
Fires when analytics.storage.removeItem is called. This event gives plugins the ability to intercept removeItem calls and abort / alter them. |
removeItemEnd |
Fires when removeItem storage is complete. |
removeItemAborted |
Fires when removeItem storage is cancelled by a plugin. |
The analytics
has a robust plugin system. Here is a list of currently available plugins:
Plugin | Stats | Version |
---|---|---|
@analytics/activity-utils User activity listener utilities |
0.1.16 | |
@analytics/amplitude Amplitude integration for 'analytics' module |
0.1.3 | |
@analytics/aws-pinpoint AWS Pinpoint integration for 'analytics' module |
0.7.12 | |
@analytics/cookie-utils Tiny cookie utility library |
0.2.12 | |
@analytics/core Lightweight analytics library for tracking events, page views, & identifying users. Works with any third party analytics provider via an extendable plugin system. |
0.12.9 | |
@analytics/countly Countly plugin for 'analytics' module |
0.21.12 | |
@analytics/crazy-egg Crazy Egg integration for 'analytics' module |
0.1.2 | |
@analytics/custify Custify integration for 'analytics' module for browser & node |
0.0.2 | |
@analytics/customerio Customer.io integration for 'analytics' module |
0.2.2 | |
@analytics/form-utils Form utility library for managing HTML form submissions & values |
0.3.13 | |
@analytics/fullstory Unofficial FullStory plugin for 'analytics' module |
0.2.6 | |
@analytics/global-storage-utils Tiny global storage utility library |
0.1.7 | |
@analytics/google-analytics Google analytics v4 plugin for 'analytics' module |
1.0.7 | |
@analytics/google-tag-manager Google tag manager plugin for 'analytics' module |
0.5.5 | |
@analytics/google-analytics-v3 Google analytics v3 plugin for 'analytics' module |
0.6.1 | |
@analytics/gosquared GoSquared integration for 'analytics' module |
0.1.3 | |
@analytics/hubspot HubSpot plugin for 'analytics' module |
0.5.1 | |
@analytics/intercom Intercom integration for 'analytics' module for browser & node |
1.0.2 | |
@analytics/listener-utils Backward compatible event listener library for attaching & detaching event handlers |
0.4.0 | |
@analytics/localstorage-utils Tiny LocalStorage utility library |
0.1.10 | |
@analytics/mixpanel Mixpanel plugin for 'analytics' module |
0.4.0 | |
@analytics/original-source-plugin Save original referral source of visitor plugin for 'analytics' pkg |
1.0.11 | |
@analytics/ownstats Ownstats integration for 'analytics' module for browser & node |
0.1.2 | |
@analytics/perfumejs Send browser performance metrics to third-party analytics providers |
0.2.1 | |
@analytics/queue-utils Dependency free queue processor |
0.1.2 | |
@analytics/redact-utils Utility library for redacting event data |
0.1.3 | |
@analytics/remote-storage-utils Storage utilities for cross domain localStorage access, with permissions |
0.4.20 | |
@analytics/router-utils Route change utilities for single page apps |
0.1.1 | |
@analytics/scroll-utils Scroll utility library to fire events on scroll |
0.1.22 | |
@analytics/segment Segment integration for 'analytics' module for browser & node |
2.1.0 | |
@analytics/session-storage-utils Tiny SessionStorage utility library |
0.0.7 | |
@analytics/session-utils Tiny session utility library |
0.2.0 | |
@analytics/simple-analytics Simple analytics plugin for 'analytics' module for browser |
0.4.0 | |
@analytics/snowplow Snowplow integration for 'analytics' module for browser & node |
0.3.3 | |
@analytics/storage-utils Storage utility with fallbacks |
0.4.2 | |
@analytics/type-utils Tiny runtime type checking utils |
0.6.2 | |
@analytics/url-utils Url utils |
0.2.3 | |
@analytics/visitor-source Get visitor source |
0.0.7 | |
analytics-cli CLI for analytics pkg |
0.0.5 | |
analytics-plugin-do-not-track Disable tracking for opted out visitors plugin for 'analytics' module |
0.1.5 | |
analytics-plugin-event-validation Event validation plugin for analytics |
0.1.2 | |
gatsby-plugin-analytics Easily add analytics to your Gatsby site |
0.2.0 | |
analytics-plugin-lifecycle-example Example plugin with lifecycle methods for 'analytics' module |
0.1.2 | |
analytics-plugin-tab-events Expose tab visibility events plugin for 'analytics' module |
0.2.1 | |
use-analytics Analytics hooks for React |
1.1.0 | |
analytics-util-params Url Parameter helper functions |
0.1.2 | |
analytics-utils Analytics utility functions used by 'analytics' module |
1.0.12 | |
analytics-plugin-window-events Expose window events plugin for 'analytics' module |
0.0.7 |
Below are plugins created outside of this repo:
Additional examples
The library is designed to work with any third-party analytics tool.
Plugins are just plain javascript objects that expose methods for analytics
to register and call.
Here is a quick example of a plugin:
// plugin-example.js
export default function pluginExample(userConfig) {
// return object for analytics to use
return {
/* All plugins require a name */
name: 'my-example-plugin',
/* Everything else below this is optional depending on your plugin requirements */
config: {
whatEver: userConfig.whatEver,
elseYouNeed: userConfig.elseYouNeed
},
initialize: ({ config }) => {
// load provider script to page
},
page: ({ payload }) => {
// call provider specific page tracking
},
track: ({ payload }) => {
// call provider specific event tracking
},
identify: ({ payload }) => {
// call provider specific user identify method
},
loaded: () => {
// return boolean so analytics knows when it can send data to third-party
return !!window.myPluginLoaded
}
}
}
name
is required for all plugins. All other methods are optional.
If you don't need to hook into page
tracking, just omit the page
key from your plugin object.
To use a plugin, import it and pass it into the plugins
array when you bootstrap analytics
.
import Analytics from 'analytics'
import pluginExample from './plugin-example.js'
const analytics = Analytics({
app: 'my-app-name',
plugins: [
pluginExample({
whatEver: 'hello',
elseYouNeed: 'there'
}),
...otherPlugins
]
})
Plugins can react to any event flowing through the analytics
library.
For example, if you wanted to trigger custom logic when analytics
bootstraps, you can attach a function handler to the bootstrap
event.
For a full list of core events, checkout events.js
.
// Example Plugin plugin.js
export default function myPlugin(userConfig) {
return {
/* Name is a required field for plugins */
name: 'my-plugin',
/* Bootstrap runs when analytics starts */
bootstrap: ({ payload, config, instance }) => {
// Do whatever on `bootstrap` event
},
pageStart: ({ payload, config, instance }) => {
// Fire custom logic before analytics.page() calls
},
pageEnd: ({ payload, config, instance }) => {
// Fire custom logic after analytics.page() calls
},
trackStart: ({ payload, config, instance }) => {
// Fire custom logic before analytics.track() calls
},
'track:customerio': ({ payload, config, instance }) => {
// Fire custom logic before customer.io plugin runs.
// Here you can customize the data sent to individual analytics providers
},
trackEnd: ({ payload, config, instance }) => {
// Fire custom logic after analytics.track() calls
},
// ... hook into other events
}
}
Using this plugin is the same as any other.
import Analytics from 'analytics'
import customerIoPlugin from '@analytics/customerio'
import myPlugin from './plugin.js'
const analytics = Analytics({
app: 'my-app-name',
plugins: [
// include myPlugin
myPlugin(),
customerIoPlugin({
trackingId: '1234'
})
...otherPlugins
]
})
Analytics plugins can provide their own custom functionality via the methods
key.
import Analytics from 'analytics'
// Example plugin with custom methods
const pluginOne = {
name: 'one',
// ... page, track, etc
// Custom functions to expose to analytics instance
methods: {
myCustomThing(one, two, three) {
const analyticsInstance = this.instance
console.log('Use full analytics instance', analyticsInstance)
},
otherCustomThing: (one, two, ...args) => {
// Arrow functions break this.instance context.
// The instance is instead injected as last arg
const analyticsInstance = args[args.length - 1]
console.log('Use full analytics instance', analyticsInstance)
},
// Async function examples
async fireCustomThing(one, two, three) {
const { track } = this.instance
track('customThing')
return 'data'
},
triggerSpecial: async (argOne, argTwo, ...args) => {
// Arrow functions break this.instance context.
// The instance is instead injected as last arg
const analyticsInstance = args[args.length - 1]
return argOne + argTwo
}
}
}
// Example plugin with custom methods
const pluginTwo = {
name: 'two',
page: () => { console.log('page view fired') }
// Custom functions to expose to analytics instance
methods: {
cookieBanner(one, two, three) {
const analyticsInstance = this.instance
console.log('Use full analytics instance', analyticsInstance)
const cookieSettings = analyticsInstance.storage.getItem('preferences-set')
if (!cookieSettings) {
// Show cookie settings
}
},
}
}
// Initialize analytics instance with plugins
const analytics = Analytics({
app: 'your-app-name',
plugins: [
pluginOne,
pluginTwo
]
})
// Using custom methods in your code
analytics.plugins.one.myCustomThing()
analytics.plugins.two.cookieBanner()
Plugins should follow this naming convention before being published to npm
analytics-plugin-{your-plugin-name}
E.g. An analytics plugin that does awesome-stuff
should be named
npm install analytics-plugin-awesome-stuff
Then submit to the list above
During development, you can turn on debug
mode. This will connect the dev tools for you to see the analytics events passing through your application visually.
import Analytics from 'analytics'
const analytics = Analytics({
app: 'my-app',
debug: true
})
Types for analytics and plugins are generated from JSDoc blocks in the code base via the tsd-jsdoc package.
We are always looking to improve type support & improve the DX of users. If you see something that can be improved let us know in an issue!
Contributions are always welcome, no matter how large or small. Before contributing, please read the code of conduct.
Clone the repo and run
$ git clone https://github.com/davidwells/analytics
$ cd analytics
$ npm install && npm run setup
The above command will set up all the packages and their dependencies.
You can watch and rebuild packages with the npm run watch
command.
npm run watch
While watch mode is activated, you can work against the demo site in examples to test out your changes on a live application.