Configuring Ember JS Analytics for GDPR

Posted on Jul 18, 2018

Ember JS GDPR

One of the issues I ran into while developing a new Ember JS app was letting the user configure tracking libraries such as Google Analytics for GDPR compliance.

Fortunately it’s not that difficult! I’ve used two packages for this: ember-metrics and ember-local-storage. If you’re conservative with your external dependencies then you could get away without using ember-local-storage and just use native Javascript for this. I chose to use it for convenience.

Make sure you install the two above mentioned packages

1
2
ember install ember-local-storage
ember install ember-metrics

Add your configuration for ember-metrics in the config/environment.js ENV hash, here’s mine as an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  //...
	metricsAdapters: [
	  {
		name: 'GoogleAnalytics',
		environments: ['development', 'production'],
		config: {
		  id: 'UA-XXXXXXXX-1',
		  anonymizeIp: true,
		  // 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: []
		}
	  }
	],
	//...

Notice that we’re using anonymizeIP. This is a feature of Google Analytics which, you guessed it, anonymises IP addresses. This is optional and will depend on your project’s requirements.

Don’t forget to add the contentSecurityPolicy settings if you’re using ember-content-security-policy (More about that in the Ember Metrics README).

1
2
3
4
5
6
7
8
9
10
11
 //...
 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'"
	}
  //...

Update your app/router.js as instructed on Ember Metrics. We’ll add ember-local-storage to check for the user’s preferences before sending tracking requests as well. I’ve named the storage scope settings, however, you can call it what you prefer. See ember-local-storage README for details.

Within the _trackPage() method we’re checking if settings.analytics is set to true, if it is then we’ll send the request. You could also make other categories, e.g. marketing and send requests for those the same way.

Ember Metrics supports a bunch of the most popular tools out of the box, including Intercom. You can also add your own custom scripts as well.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import EmberRouter from '@ember/routing/router';
import config from './config/environment';
import { inject as service } from '@ember/service';
import { scheduleOnce } from '@ember/runloop';
import { get } from '@ember/object';
import { storageFor } from 'ember-local-storage';

const Router = EmberRouter.extend({
  // Import ember local storage
  settings: storageFor('settings'),
  location: config.locationType,
  rootURL: config.rootURL,
  metrics: service(),
  didTransition() {
	this._super(...arguments);
	this._trackPage();
  },

  _trackPage() {
	scheduleOnce('afterRender', this, () => {
	  // If user wants analytics then send the request
	  if(this.get('settings.analytics')) {
		const page = this.get('url');
		const title = this.getWithDefault('currentRouteName', 'unknown');
		get(this, 'metrics').trackPage({ page, title });
	  }
	});
  }
});

Router.map(function() {
  // Your routes here
  this.route('login');
  this.route('about');
});

export default Router;

Now we’ve got the logic in place but the user has no way of updating their preference unless we expect them to update localStorage via the console (If only!).

There are a bunch of ways you can do this, all we need to do is set the settings.analytics in localStorage. I’ve chosen to use a checkbox and I’ve put it on my main index.hbs template. We’ll set the variable initially through the routes/index.js and watch for updates in controller/index.js

1
2
//templates/index.hbs
<label>{{input type="checkbox" checked=wantsAnalytics }} Enable Analytics</label>

Note that by default we’re setting analytics to false. The user will have to opt-in manually to send their analytical data.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//routes/index.js
import Route from '@ember/routing/route';
import { storageFor } from 'ember-local-storage';

export default Route.extend({
  settings: storageFor('settings'),
  setupController(controller) {
	this._super(...arguments)
    // Set default to false to be opt-in, or true to be opt out
	var wantsAnalytics = (this.get('settings.analytics') !== undefined) ? this.get('settings.analytics') : false;
	controller.set('wantsAnalytics', wantsAnalytics);
  },
});

In the controller we observe the input checkbox value, once it changes we update the local storage to reflect the new value.

1
2
3
4
5
6
7
8
9
10
11
12
//controllers/index.js
import Controller from '@ember/controller';
import { storageFor } from 'ember-local-storage';

export default Controller.extend({
  settings: storageFor('settings'),
  wantsAnalytics: true,
  updateAnalytics: function() {
	this.set('settings.analytics', this.get('wantsAnalytics'));
  }.observes('wantsAnalytics')
});

And that’s all there is to it! You can see this in action on your local environment by opening the developer console. Google Analytics is set to debug mode via Ember Metrics, so you can see when a page view is sent.

Like this article? Sign up to updates - no spam!