• Stars
    star
    367
  • Rank 116,257 (Top 3 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 9 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Send data to multiple analytics integrations without re-implementing new API

ember-metrics

Send data to multiple analytics services without re-implementing new API

Download count all time npm version Build Status Ember Observer Score

This addon adds a simple metrics service to your app that makes it simple to send data to multiple analytics services without having to implement a new API each time.

Using this addon, you can easily use bundled adapters for various analytics services, and one API to track events, page views, and more. When you decide to add another analytics service to your stack, all you need to do is add it to your configuration, and that's it!

Writing your own adapters for currently unsupported analytics services is easy too. If you'd like to then share it with the world, submit a pull request and we'll add it to the bundled adapters.

Currently supported services and options

  1. GoogleAnalytics

  2. GoogleAnalyticsFour

    • id: Measurement Id, e.g. G-XXXX
    • options: optional An object which will be directly passed to the configuration tag, e.g.:
    options = {
      anonymize_ip: true,
      debug_mode: environment === 'development',
    };

    By default GA4 automatically tracks page views when the history locations changes. This means that this.metrics.trackPage() is ignoreded by default. However, if you want to track the page views manually, you need to set send_page_view: false inside the options. To avoid double counting page views make sure enhanced measurement is configured correctly. Typically, this means disabling Page changes based on browser history events under the advanced settings of the page views section.

  3. Mixpanel

  4. GoogleTagManager

    • id: Container ID, e.g. GTM-XXXX

    • dataLayer: An array containing a single POJO of information, e.g.:

    dataLayer = [
      {
        pageCategory: 'signup',
        visitorType: 'high-value',
      },
    ];
    • envParams: A string with custom arguments for configuring GTM environments (Live, Dev, etc), e.g.:
    envParams: 'gtm_auth=xxxxx&gtm_preview=env-xx&gtm_cookies_win=x';
  5. Segment

  6. Piwik

  7. Intercom

  8. Facebook Pixel

    dataProcessingOptions: {
      method: ['LDU'],
      country: 1,
      state: 1000
    }
  9. Amplitude

  10. Azure App Insights

  11. Pendo

  12. MatomoTagManager

  13. Hotjar

Community adapters

  1. Adobe Dynamic Tag Management

  2. Simple Analytics

Installing The Addon

ember install ember-metrics

Compatibility

  • Ember.js v3.20 or above
  • Ember CLI v3.20 or above
  • Node.js v12 or above

Configuration

To setup, you should first configure the service through config/environment:

module.exports = function (environment) {
  var ENV = {
    metricsAdapters: [
      {
        name: 'GoogleAnalytics',
        environments: ['development', 'production'],
        config: {
          id: 'UA-XXXX-Y',
          // Use `analytics_debug.js` in development
          debug: environment === 'development',
          // Use verbose tracing of GA events
          trace: environment === 'development',
          // Ensure development env hits aren't sent to GA
          sendHitTask: environment !== 'development',
          // Specify Google Analytics plugins
          require: ['ecommerce'],
        },
      },
      {
        name: 'GoogleAnalyticsFour',
        environments: ['production'],
        config: {
          id: 'G-XXXX',
          options: {
            anonymize_ip: true,
            debug_mode: environment === 'development',
          },
        },
      },
      {
        name: 'Mixpanel',
        environments: ['production'],
        config: {
          token: '0f76c037-4d76-4fce-8a0f-a9a8f89d1453',
        },
      },
      {
        name: 'Segment',
        environments: ['production'],
        config: {
          key: '4fce-8a0f-a9a8f89d1453',
        },
      },
      {
        name: 'Piwik',
        environments: ['production'],
        config: {
          piwikUrl: 'http://piwik.my.com',
          siteId: 42,
        },
      },
      {
        name: 'Intercom',
        environments: ['production'],
        config: {
          appId: 'def1abc2',
        },
      },
      {
        name: 'FacebookPixel',
        environments: ['production'],
        config: {
          id: '1234567890',
          dataProcessingOptions: {
            method: ['LDU'],
            country: 1,
            state: 1000,
          },
        },
      },
      {
        name: 'Amplitude',
        environments: ['production'],
        config: {
          apiKey: '12345672daf5f3515f30f0000f1f0000cdfe433888',
          options: {
            trackingOptions: {
              ip_address: false,
            },
            // ...other amplitude configuration options
            // https://developers.amplitude.com/#sdk-advanced-settings
          },
        },
      },
      {
        name: 'AzureAppInsights',
        environments: ['production'],
        config: {
          instrumentationKey: '123',
          // ...other appInsights configuration options
          // https://github.com/microsoft/ApplicationInsights-JS#configuration
        },
      },
      {
        name: 'Pendo',
        environments: ['production'],
        config: {
          apiKey: '123456789',
        },
      },
      {
        name: 'LocalAdapter',
        environments: ['all'], // default
        config: {
          foo: 'bar',
        },
      },
      {
        name: 'MatomoTagManager',
        environments: ['production'],
        config: {
          matomoUrl: 'matomo.my.com',
          containerId: 'acd123',
        },
      },
      {
        name: 'Hotjar',
        environments: ['production'],
        config: {
          siteId: '123456789',
        },
      },
    ],
  };
};

Adapter names are PascalCased. Refer to the list of supported adapters above for more information.

The metricsAdapters option in ENV accepts an array of objects containing settings for each analytics service you want to use in your app in the following format:

/**
 * @param {String} name Adapter name
 * @param {Array} environments Environments that the adapter should be activated in
 * @param {Object} config Configuration options for the service
 */
{
  name: 'Analytics',
  environments: ['all'],
  config: {}
}

Values in the config portion of the object are dependent on the adapter. If you're writing your own adapter, you will be able to retrieve the options passed into it:

// Example adapter
export default class ExampleAdapter extends BaseAdapter {
  init() {
    const { apiKey, options } = this.config;
    this.setupService(apiKey);
    this.setOptions(options);
  }
}

To only activate adapters in specific environments, you can add an array of environment names to the config, as the environments key. Valid environments are:

  • development
  • test
  • production
  • all (default, will be activated in all environments)

Content Security Policy

If you're using ember-cli-content-security-policy, you'll need to modify the content security policy to allow loading of any remote scripts. In config/environment.js, add this to the ENV hash (modify as necessary):

// example for loading Google Analytics
contentSecurityPolicy: {
  'default-src': "'none'",
  'script-src': "'self' www.google-analytics.com",
  'font-src': "'self'",
  'connect-src': "'self' www.google-analytics.com",
  'img-src': "'self'",
  'style-src': "'self'",
  'media-src': "'self'"
}

Usage

In order to use the addon, you must first configure it, then inject it into any Object registered in the container that you wish to track. For example, you can call a trackPage event across all your analytics services whenever you transition into a route, like so:

// app/routes/application.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

export default class ApplicationRoute extends Route {
  @service metrics;
  @service router;

  constructor() {
    super(...arguments);

    this.router.on('routeDidChange', () => {
      const page = this.router.currentURL;
      const title = this.router.currentRouteName || 'unknown';

      this.metrics.trackPage({ page, title });
    });
  }
}

If you wish to only call a single service, just specify it's name as the first argument:

// only invokes the `trackPage` method on the `GoogleAnalyticsAdapter`
metrics.trackPage('GoogleAnalytics', {
  title: 'My Awesome App',
});

Context

Often, you may want to include information like the current user's name with every event or page view that's tracked. Any properties that are set on metrics.context will be merged into options for every Service call.

this.metrics.context.userName = 'Jimbo';
this.metrics.trackPage({ page: 'page/1' }); // { userName: 'Jimbo', page: 'page/1' }

API

Service API

There are 4 main methods implemented by the service, with the same argument signature:

  • trackPage([analyticsName], options)

    This is commonly used by analytics services to track page views. Due to the way Single Page Applications implement routing, you will need to call this on the activate hook of each route to track all page views.

  • trackEvent([analyticsName], options)

    This is a general purpose method for tracking a named event in your application.

  • identify([analyticsName], options)

    For analytics services that have identification functionality.

  • alias([analyticsName], options)

    For services that implement it, this method notifies the analytics service that an anonymous user now has a unique identifier.

If an adapter implements specific methods you wish to call, then you can use invoke

  • invoke(method, [analyticsName], options)

    metrics.invoke('trackLink', 'Piwik', {
      url: 'my_favorite_link',
      linkType: 'download',
    });

Lazy Initialization

If your app implements dynamic API keys for various analytics integration, you can defer the initialization of the adapters. Instead of configuring ember-metrics through config/environment, you can call the following from any Object registered in the container:

// app/routes/application.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

export default class ApplicationRoute extends Route {
  @service metrics;

  afterModel(model) {
    const id = model.googleAnalyticsKey;

    this.metrics.activateAdapters([
      {
        name: 'GoogleAnalytics',
        environments: ['all'],
        config: {
          id,
        },
      },
    ]);
  }
}

Because activateAdapters is idempotent, you can call it as many times as you'd like. However, it will not reinstantiate existing adapters.

Since ember-metrics now automatically removes all unused adapters, it's also important to force the inclusion of the adapter via config/environment. NOTE: If the adapter is already defined in the metricsAdapters array of config/environment then this step is not necessary.

// config/environment
module.exports = function(environment) {
  var ENV = {
    'ember-metrics': {
      includeAdapters: ['google-analytics']
    }
  };

  return ENV;

Writing Your Own Adapters

First, generate a new Metrics Adapter:

$ ember generate metrics-adapter foo-bar

This creates app/metrics-adapters/foo-bar.js and a unit test at tests/unit/metrics-adapters/foo-bar-test.js, which you should now customize.

Required Methods

The standard contracts are optionally defined, but init and willDestroy must be implemented by your adapter.

init

This method is called when an adapter is activated by the service. It is responsible for adding the required script tag used by the integration, and for initializing it.

willDestroy

When the adapter is destroyed, it should remove its script tag and property. This is usually defined on the window.

Usage

Once you have implemented your adapter, you can add it to your app's config, like so:

module.exports = function (environment) {
  var ENV = {
    metricsAdapters: [
      {
        name: 'MyAdapter',
        environments: ['all'],
        config: {
          secret: '29fJs90qnfEa',
          options: {
            foo: 'bar',
          },
        },
      },
    ],
  };
};

Contributors

We're grateful to these wonderful contributors who've contributed to ember-metrics:

Contributing

See the Contributing guide for details.

License

This project is licensed under the MIT License.

More Repositories

1

ember-electron

⚑ Build, test, compile and package desktop apps with Ember and Electron
JavaScript
806
star
2

ember-cp-validations

Ember computed property based validations
JavaScript
443
star
3

ember-changeset

Ember.js flavored changesets, inspired by Ecto
JavaScript
431
star
4

ember-moment

JavaScript
399
star
5

ember-infinity

⚑ Simple, flexible Infinite Scroll for Ember CLI Apps.
JavaScript
377
star
6

ember-data-model-fragments

Ember Data addon to support nested JSON documents
JavaScript
371
star
7

ember-cli-flash

Simple, highly configurable flash messages for ember-cli
JavaScript
355
star
8

ember-light-table

Lightweight, contextual component based table for Ember
JavaScript
312
star
9

ember-data-factory-guy

Factories and helper functions for (unit, integration, acceptance) testing + development scenarios with Ember Data
JavaScript
302
star
10

ember-sortable

Sortable UI primitives for Ember.js
JavaScript
295
star
11

ember-burger-menu

An off-canvas sidebar component with a collection of animations and styles using CSS transitions
JavaScript
279
star
12

ember-cli-sass

Use node-sass to preprocess your ember-cli app's files, with support for sourceMaps and include paths
JavaScript
276
star
13

ember-notify

Notification messages for your Ember.js app
JavaScript
264
star
14

ember-collection

An efficient incremental rendering component for Ember.js with support for custom layouts and large lists
JavaScript
236
star
15

ember-changeset-validations

Validations for ember-changeset
JavaScript
219
star
16

ember-file-upload

File uploads for Ember apps
TypeScript
201
star
17

emberx-select

Select component for Ember based on the native html select element.
JavaScript
200
star
18

ember-keyboard

An Ember.js addon for the painless support of keyboard events
JavaScript
177
star
19

ember-pikaday

A datepicker component for Ember CLI projects.
JavaScript
159
star
20

ember-impagination

An Ember Addon that puts the fun back in asynchronous, paginated datasets
JavaScript
122
star
21

active-model-adapter

Adapters and Serializers for Rails's ActiveModel::Serializers
TypeScript
102
star
22

ember-cli-hot-loader

An early look at what hot reloading might be like in the ember ecosystem
JavaScript
99
star
23

ember-autoresize

Autoresize for Ember Components
JavaScript
88
star
24

ember-cli-windows

🚀 Improve Ember-Cli Performance on Windows
JavaScript
79
star
25

ember-set-helper

A better `mut` helper
JavaScript
68
star
26

ember-inputmask

Ember wrapper around Inputmask.js
JavaScript
68
star
27

ember-collapsible-panel

An unopinionated, zero-dependency panel and accordion
JavaScript
57
star
28

ember-qunit-nice-errors

Because expected true, result false is not enough!
JavaScript
56
star
29

ember-cli-ifa

Ember CLI addon for injecting fingerprinted asset map file into Ember app
JavaScript
54
star
30

emberx-file-input

A tiny Ember component which does one thing and only: select files beautifully.
JavaScript
52
star
31

ember-cognito

AWS Amplify/Cognito and ember-simple-auth integration
JavaScript
32
star
32

ember-validators

A collection of EmberJS validators
JavaScript
24
star
33

ember-cli-bugsnag

Integrates Bugsnag reporting service into your Ember CLI app.
JavaScript
20
star
34

ember-stripe-elements

A simple Ember wrapper for Stripe Elements
JavaScript
18
star
35

ember-popper-modifier

An Ember modifier for working with Popper.js.
TypeScript
14
star
36

ember-launch-darkly

A modern Ember addon to wrap the Launch Darkly service
JavaScript
13
star
37

ember-require-module

Dynamically require modules
JavaScript
7
star
38

ember-indexeddb-adapter

Ember Data adapter for IndexedDB
JavaScript
4
star
39

program-guidelines

Checklist and guidelines for the Adopted Ember Addons org.
JavaScript
3
star
40

ember-cli-deploy-new-relic-sourcemap

Ember CLI Deploy plugin to deploy source maps to new relic
JavaScript
2
star