Crosslytics
![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)
Tired of writing repetitive code to send the same analytics data to all your different tracking services? Or formatting the same data slightly differently for each service, like using eventAction
for Google Analytics but event_name
for Intercom?
Use Crosslytics for a unified event definition and analytics reporting API: Define events once and report them to all your analytics services with a single call. We've also abstracted the services themselves into a pluggable Tracker architecture so you can use only the services you need and quickly add support for new ones.
Why not use Segment? We didn't want to add another hosted service dependency, so we came up with a light-weight library to send telemetry directly. The meat of Crosslytics lies with its unified datamodels. The models are in fact based on the Segment spec, so usage semantics should actually be very similar.
Usage
Define events
Define some events by subclassing TrackedEvent
. Since the Crosslytics library is isomorphic, you only have to do this once. You can then share the same event definitions between your client and server code:
type DashboardPanelEventArgs = {
'Panel ID': string,
'Panel Type'?: number,
'Panel Name'?: string
};
export class DashboardPanelCreated implements TrackedEvent<DashboardPanelEventArgs> {
readonly name = 'DashboardPanel Created';
readonly category = 'Dashboard';
readonly argPriority: (keyof DashboardPanelEventArgs)[] = [
'Panel ID',
'Panel Type',
'Panel Name'
];
}
Server-side
Do a one-time setup of trackers in your application code using Express middleware:
import * as express from 'express';
import { Crosslytics, Identity } from 'crosslytics';
import { GoogleAnalyticsTracker } from 'crosslytics-node-google-analytics-tracker';
const app = express();
app.use((req: Request, res: Response, next: NextFunction) => {
req.telemetry = new Crosslytics();
const gaTracker = new GoogleAnalyticsTracker('UA-12345678-9');
req.telemetry.trackers.set(gaTracker.id, gaTracker);
req.telemetry.identify({userId: ''});
next();
});
Now you can report events to all trackers using a single call:
import { DashboardPanelCreated } from './events';
app.route('panel').post((req: Request, res: Response, next: NextFunction) => {
...
const ev = new DashboardPanelCreated({
'Panel ID': '123456',
'Panel Name': 'Test Panel'
});
req.telemetry.track(ev);
});
Client-side
We recommend adding analytics metadata to Redux Actions. For example, you could include an action.analytics
property when you want an action to be tracked. This way, you can setup Redux middleware to report analytics and greatly reduce the amount of tracking code you need to write.
First, do a one-time setup of trackers and create a middleware:
import { Action, Middleware } from 'redux';
import { Crosslytics, Identity, TrackedEvent } from 'crosslytics';
import { GoogleAnalyticsTracker } from 'crosslytics-browser-google-analytics-tracker';
export const crosslytics = new Crosslytics();
const gaTracker = new GoogleAnalyticsTracker('UA-12345678-9');
crosslytics.trackers.set(gaTracker.id, gaTracker);
export function analyticsMiddleware(crosslytics: Crosslytics): Middleware {
return () => next => <T, A extends TrackableAction<T>>(action: A) => {
if (action.analytics) {
crosslytics.track(action.analytics);
}
return next(action);
};
}
interface TrackableAction<T> extends Action { analytics?: TrackedEvent<T> }
Then add the middleware to your Redux store (also one-time):
import { createStore, applyMiddleware } from 'redux';
import { analyticsMiddleware, crosslytics } from './middelware.ts';
let store = createStore(
reducers,
applyMiddleware(
analyticsMiddleware
)
);
const history = createHistory();
history.listen(location => crosslytics.page({ url: location.pathname }));
Finally, you can now just add an action.analytics
property to your actions and the events will be tracked automatically by the middleware. An example async action creator:
import { DashboardPanelCreated } from './events';
export const panelCreated = (panel) => {
const ev = new DashboardPanelCreated({
'Panel ID': panel.id,
'Panel Name': panel.name
});
return {
type: 'PANEL_CREATED',
payload: panel,
analytics: ev
};
};
Trackers
Docs coming soon