Analytics 📊
A lightweight, extendable analytics library designed to work with any third party analytics provider to track page views, custom events, & identify users.
The analytics
library allows users to:
- Connect with your favorite analytics providers
- Trigger custom logic based on user activity
- Extend with functionality via plugins
- Easily allow visitors to opt out of tracking
- ... and lots more
Table of Contents
Click to expand
Features
Why
Companies frequently change analytics & collection requirements. This results in adding & removing analytic services a painful time consuming process.
This library aims to solves that with a simple pluggable abstraction layer.
Philosophy
You should never be locked into a tool
To add or remove an analytics provider adjust the plugins
you load into analytics
.
Install
npm install analytics --save
Or as a script tag:
<script src="https://unpkg.com/analytics/dist/analytics.min.js"></script>
Usage
import Analytics from 'analytics'
import googleAnalyticsPlugin from 'analytics-plugin-ga'
import customerIOPlugin from 'analytics-plugin-customerio'
const analytics = Analytics({
app: 'my-app-name',
version: 100,
plugins: [
googleAnalyticsPlugin({
trackingId: 'UA-121991291',
}),
customerIOPlugin({
siteId: '123-xyz'
})
]
})
analytics.page()
analytics.track('userPurchase', {
price: 20
item: 'pink socks'
})
analytics.identify('user-id-xyz', {
firstName: 'bill',
lastName: 'murray',
email: 'da-coolest@aol.com'
})
Node.js usage
For ES6/7 javascript you can import Analytics from 'analytics'
for normal node.js usage you can import like so:
const { Analytics } = require('analytics')
const analytics = Analytics({
app: 'my-app-name',
version: 100,
plugins: [
googleAnalyticsPlugin({
trackingId: 'UA-121991291',
}),
customerIOPlugin({
siteId: '123-xyz'
})
]
})
analytics.page()
Browser usage
When importing global analytics
into your project from a cdn the library is expose via a global _analytics
variable.
Call _analytics.init
to create an analytics instance.
<script src="https://unpkg.com/analytics/dist/analytics.min.js"></script>
<script>
const Analytics = _analytics.init({
app: 'my-app-name',
version: 100,
...plugins
})
Analytics.track()
window.Analytics = Analytics
</script>
Demo
See Analytics Demo for a site example.
API
Below is the core API analytics expose once initialized.
Configuration
Analytics library
Arguments
- config
object
- analytics core config - [config.app] (optional)
string
- Name of site / app - [config.version] (optional)
string
- Version of your app - [config.plugins] (optional)
array
- Array of analytics plugins
Example
import Analytics from 'analytics'
const analytics = Analytics({
app: 'my-awesome-app',
plugins: [
...importedPlugins
]
})
analytics.identify
Identify a user. This will trigger identify
calls in any installed plugins and will set user data in localStorage
Arguments
- userId
String
- Unique ID of user - [traits] (optional)
Object
- Object of user traits - [options] (optional)
Object
- Options to pass to identify call - [callback] (optional)
Function
- Callback function after identify completes
Example
analytics.identify('xyz-123')
analytics.identify('xyz-123', {
name: 'steve',
company: 'hello-clicky'
})
analytics.identify('xyz-123', {}, {
plugins: {
segment: false
}
})
analytics.identify('xyz-123', () => {
console.log('do this after identify')
})
analytics.track
Track an analytics event. This will trigger track
calls in any installed plugins
Arguments
- eventName
String
- Event name - [payload] (optional)
Object
- Event payload - [options] (optional)
Object
- Event options - [callback] (optional)
Function
- Callback to fire after tracking completes
Example
analytics.track('buttonClicked')
analytics.track('itemPurchased', {
price: 11,
sku: '1234'
})
analytics.track('cartAbandoned', {
items: ['xyz', 'abc']
}, {
plugins: {
segment: false
}
})
analytics.track('newsletterSubscribed', () => {
console.log('do this after track')
})
analytics.page
Trigger page view. This will trigger page
calls in any installed plugins
Arguments
- [data] (optional)
String
- Page data overrides. - [options] (optional)
Object
- Page tracking options - [callback] (optional)
Function
- Callback to fire after page view call completes
Example
analytics.page()
analytics.page({
url: 'https://google.com'
})
analytics.page({}, {
plugins: {
segment: false
}
})
analytics.page(() => {
console.log('do this after page')
})
analytics.user
Get user data
Arguments
- [key] (optional)
String
- dot.prop.path of user data. Example: 'traits.company.name'
Example
const userData = analytics.user()
const userId = analytics.user('userId')
const companyName = analytics.user('traits.company.name')
analytics.reset
Clear all information about the visitor & reset analytic state.
Arguments
- [callback] (optional)
Function
- Handler to run after reset
Example
analytics.reset()
analytics.ready
Fire callback on analytics ready event
Arguments
- callback
Function
- function to trigger when all providers have loaded
Example
analytics.ready() => {
console.log('all plugins have loaded or were skipped', payload)
})
analytics.on
Attach an event handler function for analytics lifecycle events.
Arguments
- name
String
- Name of event to listen to - callback
Function
- function to fire on event
Example
analytics.on('track', ({ payload }) => {
console.log('track call just happened. Do stuff')
})
const removeListener = analytics.on('track', ({ payload }) => {
console.log('This will never get called')
})
removeListener()
analytics.once
Attach a handler function to an event and only trigger it only once.
Arguments
- name
String
- Name of event to listen to - callback
Function
- function to fire on event
Example
analytics.once('track', ({ payload }) => {
console.log('This will only triggered once when analytics.track() fires')
})
const listener = analytics.once('track', ({ payload }) => {
console.log('This will never get called b/c listener() is called')
})
listener()
analytics.getState
Get data about user, activity, or context. Access sub-keys of state with dot.prop
syntax.
Arguments
- [key] (optional)
string
- dot.prop.path value of state
Example
analytics.getState()
analytics.getState('context.offline')
analytics.enablePlugin
Enable analytics plugin
Arguments
- plugins
String
|Array
- name of plugins(s) to disable - [callback] (optional)
Function
- callback after enable runs
Example
analytics.enablePlugin('google')
analytics.enablePlugin(['google', 'segment'])
analytics.disablePlugin
Disable analytics plugin
Arguments
- name
String
|Array
- name of integration(s) to disable - callback
Function
- callback after disable runs
Example
analytics.disablePlugin('google')
analytics.disablePlugin(['google', 'segment'])
analytics.storage
Storage utilities for persisting data.
These methods will allow you to save data in localStorage, cookies, or to the window.
Example
const { storage } = analytics
storage.getItem('storage_key')
storage.setItem('storage_key', 'value')
storage.removeItem('storage_key')
analytics.storage.getItem
Get value from storage
Arguments
- key
String
- storage key - [options] (optional)
Object
- storage options
Example
analytics.storage.getItem('storage_key')
analytics.storage.setItem
Set storage value
Arguments
- key
String
- storage key - value any - storage value
- [options] (optional)
Object
- storage options
Example
analytics.storage.setItem('storage_key', 'value')
analytics.storage.removeItem
Remove storage value
Arguments
- key
String
- storage key - [options] (optional)
Object
- storage options
Example
analytics.storage.removeItem('storage_key')
Events
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.enablePlugin()' is called |
disablePlugin | Fires when 'analytics.disablePlugin()' is called |
loadPlugin | Fires when 'analytics.loadPlugin()' 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. |
Analytic plugins
The analytics
has a robust plugin system. Here is a list of currently available plugins:
Creating analytics plugins
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:
export default function pluginExample(userConfig) {
return {
NAMESPACE: 'my-example-plugin',
config: {
whatEver: userConfig.whatEver,
elseYouNeed: userConfig.elseYouNeed
},
initialize: ({ config }) => {
},
page: ({ payload }) => {
},
track: ({ payload }) => {
},
identify: ({ payload }) => {
},
loaded: () => {
return !!window.myPluginLoaded
}
}
}
NAMESPACE
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
]
})
React to any event
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
.
export default function myPlugin(userConfig) {
return {
NAMESPACE: 'my-plugin',
bootstrap: ({ payload, config, instance }) => {
},
pageStart: ({ payload, config, instance }) => {
},
pageEnd: ({ payload, config, instance }) => {
},
trackStart: ({ payload, config, instance }) => {
},
'track:customerio': ({ payload, config, instance }) => {
},
trackEnd: ({ payload, config, instance }) => {
},
}
}
Using this plugin is the same as any other.
import Analytics from 'analytics'
import customerIoPlugin from 'analytics-plugin-customerio'
import myPlugin from './plugin.js'
const analytics = Analytics({
app: 'my-app-name',
plugins: [
myPlugin(),
customerIoPlugin({
trackingId: '1234'
})
...otherPlugins
]
})
Optional - Using middleware
Alternatively, you can also attach any middleware functionality you'd like from the redux
ecosystem.
const logger = store => next => action => {
if (action.type) {
console.log(`>> analytics dispatching ${action.type}`, JSON.stringify(action))
}
return next(action)
}
export default logger
Using this plugin is the same as any other.
import Analytics from 'analytics'
import loggerPlugin from './logger-plugin.js'
const analytics = Analytics({
app: 'my-app-name',
plugins: [
...otherPlugins,
loggerPlugin
]
})
Opt out example plugin
This is a vanilla redux middleware that will opt out users from tracking. There are many ways to implement this type of functionality using analytics
const optOutMiddleware = store => next => action => {
const { type } = action
if (type === 'trackStart' || type === 'pageStart' || type === 'trackStart') {
const { user } = store.getState()
if (user && user.traits.optOut) {
return next({
...action,
...{
abort: true,
reason: 'User opted out'
},
})
}
}
return next(finalAction)
}
export default optOutMiddleware
Plugin Naming Conventions
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
Development
During development you can turn on debug
mode. This will connect redux dev tools for you to visually see the analytics events passing through your application.
[GIF]
import Analytics from 'analytics'
const analytics = Analytics({
app: 'my-app-name',
debug: true
})
Contributing
Contributions are always welcome, no matter how large or small. Before contributing,
please read the code of conduct.