Skip to content

Instantly share code, notes, and snippets.

@danbahrami
Last active February 4, 2020 14:36
Show Gist options
  • Save danbahrami/1e7c1e694df6a2667aaec4505a285e71 to your computer and use it in GitHub Desktop.
Save danbahrami/1e7c1e694df6a2667aaec4505a285e71 to your computer and use it in GitHub Desktop.

Tracking

This is our JS tracking library that we use to define and send events to Backtrack. Backtrack then forwards the events to Mixpanel.

It's available from the rest of Polecat under an alias '@Tracking'.

Usage

The main reason we have this library is to add order to our Mixpanel events. For that reason events are defined with a schema. The properties dispatched with events are then validated against the schema in Backtrack before being forwarded to Mixpanel.

Sending events

Sending events that are already defined is simple.

import { trackEvent } from '@Tracking';
import { widgetDeleted } from '@Tracking/events';

const onDelete = () => {
  trackEvent(widgetDeleted({
    'Widget ID': '1234',
    'Integration Name': 'Zendesk Support',
  }));
};

Defining events

Similar to Redux actions, each event has an event creator defined up front. You'll find these events in the ./events directory, categorised by type.

We have a helper defineEvent that accepts

  • name (String): The event name
  • schemaTypes (Object): The schema definition for the event (See SchemaTypes section)
  • ...contexts (Object): Any contexts for the event (See Contexts section)
import defineEvent from '@Tracking/define-event';
import SchemaTypes from '@Tracking/schema-types';

export const widgetDeleted = defineEvent('Widget - deleted', {
  'Widget ID': SchemaTypes.string.isRequired,
  'Integration Name': SchemaTypes.string.isRequired,
});

SchemaTypes

The Schema Types package is essentially a slimmed down version of PropTypes containing the following types:

  • SchemaTypes.string
  • SchemaTypes.number
  • SchemaTypes.bool
  • SchemaTypes.oneOf([])

Contexts

There might be cases where several events have to contain the same properties. For example, all Dashboard related events may require a Dashboard ID. As Dashboard ID is stored in our application (Redux) state we can automatically inject it into events using a context.

Contexts are kept in the ./contexts directory, each context is a single object that contains a schema type definition and a context function.

import SchemaTypes from '@Tracking/schema-types';

const dashboardContext = {
  schema: {
    'Dashboard ID': SchemaTypes.string.isRequired,
    'Layout type': SchemaTypes.oneOf(['classic', 'box', 'container']).isRequired,
  },
  context: ({ reduxState }) => ({
    'Dashboard ID': reduxState.currentDashboard.id,
    'Layout type': reduxState.currentDashboard.type,
  })
}

You can then pass that context to events when they are defined.

import defineEvent from '@Tracking/define-event';
import SchemaTypes from '@Tracking/schema-types';
import dashboardContext from '@Tracking/contexts/dashboard-context';

export const dashboardTitleChanged = defineEvent(
  'Dashboard - Title changed',
  {
    'New Title': PropTypes.string,
  },
  dashboardContext,
);

Now, any time you dispatch the dashboardTitleChanged event, the Dashboard ID and Layout type will be automatically injected into the properties.

Note: Properties passed to the event creator manually will override any property from contexts that has the same key.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment