We're huge fans of open-source, and absolutely we love getting good contributions to analytics.js! These docs will tell you everything you need to know about how to add your own integration to the library with a pull request, so we can merge it in for everyone else to use.
To start, we'll get you set up with our development environment. All of our development scripts and helpers are written in node.js, so you'll want to install that first by going to nodejs.org.
Then after forking analytics.js-integrations just cd
into the folder and run make
:
$ cd analytics.js-integrations
$ make
That will install all of our npm and component dependencies and compile the latest version of the development build to test against. You can now add your changes to the library, and run make test
to make sure everything is passing still.
The commands you'll want to know for development are:
$ make # re-compiles the development build of analytics.js for testing
$ make test # runs all of the tests in your terminal
$ make test-browser # runs all of the tests in your browser, for nicer debugging
To start, you need a couple of tools that will help you integrate as fast as possible:
- Khaos (
npm i -g khaos
) - khaos-analytics.js-integration (
khaos install segmentio/khaos-analytics.js-integration analytics.js-integration
)
Once you have those tools installed, cd
into your fork and run:
$ khaos create analytics.js-integration lib/<slug>
Khaos will ask you a couple of question and create the integration skeleton for you! See our tracking API to check what each method does.
We've written analytics.js to be very modular, so that adding new integrations is incredibly easy. The basic idea is that the analytics
singleton has a list of Integration
constructors, all keyed by name. For example:
analytics.Integrations;
// {
// 'Google Analytics': [function],
// 'Mixpanel': [function],
// 'Customer.io': [function],
// ...
// }
To add a new integration to the list we expose an analytics.addIntegration
method, which you just need to pass a constructor. You can create your own integration constructor with our analytics.js-integration component. (That's how all of the default integrations are created too.)
Then when you call analytics.initialize
, it will create a new instance of all of the integrations you give it settings for.
To get started, inside your integration file, just require the analytics.js-integration factory like so:
var integration = require('analytics.js-integration');
And then you can make your own integration constructor by passing it a name
:
var integration = require('analytics.js-integration');
var MyIntegration = integration('My Integration');
Once you have the prototype created, you just need to add any of the methods in our Tracking API to the prototype
. For example, an integration that implements initialize
and identify
might look like this:
var MyIntegration = integration('My Integration')
.option('apiKey', null);
/**
* Initialize.
*
* @param {Object} page
*/
MyIntegration.prototype.initialize = function (page) {
// do stuff with `this.options` to initialize your library
};
/**
* Identify.
*
* @param {String} id (optional)
* @param {Object} traits (optional)
* @param {Object} options (optional)
*/
MyIntegration.prototype.identify = function (id, traits, options) {
// do stuff with `id` or `traits`
};
To get a good idea of how adding an integration works, check out some of our existing integration files.
Note: if you wanted to add your own private integration, you'd do exactly the same thing, just inside your own codebase! But public ones are way more awesome because everyone gets to share them and improve them...
Every contribution you make to analytics.js should be accompanied by matching tests. If you look inside of the test.js
file of any integration, you'll see we're pretty serious about this. That's because:
- analytics.js runs on tons of different types of browsers, operating systems, etc. and we want to make sure it runs well everywhere.
- It lets us add new features much, much more quickly.
- We aren't insane.
When adding your own integration, the easiest way to figure out what major things to test is to look at everything you've added to the integration prototype
. You'll want to write testing groups for #initialize
, #load
, #identify
, #track
, etc. And each group should test all of the expected functionality.
The most important thing to writing clean, easy-to-manage integrations is to keep them small and clean up after each test, so that the environment is never polluted by an individual test. For example, in the /lib/customerio/test.js
#identify
tests you'll notice that we use the beforeEach
and afterEach
to make sure that user and sinon.spy state is cleared before and after each test. That way no individual test failing means all of the rest of the tests fail too. (Avoid domino situations!)
If you run into any questions, check out a few of our existing test files to see how we've done it.
To help make contributing easy, here's all the things you need to remember:
- Add your integration file to
/lib
. - Create a new Integration constructor with the
integration
factory component. - Add your integration's default options with
.option()
. - Add an
initialize
method to your integration'sprototype
. - Add methods you want to support to the
prototype
. (identify
,track
,pageview
, etc.) - Write tests for all of your integration's logic.
- Run the tests and get everything passing.
- Commit your changes with a nice commit message.
- Submit your pull request.
- Add a vector logo to the pull request comments if you want it merged into Segment too!