Build a Free Electron Analytics Stack with Google Analytics and Redux

Posted on 2018-09-28

If you’re looking here, there’s a good chance you already realized that there aren’t many options for wiring your Electron app with analytics.

Currently, there’s nothing great like Firebase Analytics for Electron. An in fact, being that Electron is a desktop app, I don’t see a great reason why there shouldn’t be. In many ways Electron apps are similar to mobile apps in that regard and so lend themselves well to getting a ton of value from analytics integration. PS — there’s Sentry integration for Electron, but it’s not analytics, and I found it flaky / buggy so far for some use cases.

Since Electron apps are Desktop apps and not websites, there’s a good chance your users would be using your app without an internet connection or with an intermittent connection. For that reason any solution you choose should be robust and take that into account. What’s more, if you assumed you’ll just add the usual Javascript universal analyics tag to your Electron main HTML page, you’re in for a surprise; not only will you lose events once your app goes offline, but Google Analytics will also:

  • Require a real http protocol behind your app, which isn't what's there. Your app is behind a file:// protocol and so Google Analytics will fail silently (unless debug variant of Google Analytics is used and tracing enabled)
  • Try to use cookies, and fail silently again
  • Have nothing to work with in terms of identifying pages
  • Work outside of fetch and so you won't see anything in the Network tab in your Electron devtools

redux-beacon-electron

If you have an app powered by Redux, you’re already in a perfect state to integrate analytics. In fact you can see every action in your app architecture as an analytics event, and since actions in Redux are granular and isolated, it’s extremely simple to turn them into analytics event.

Redux Beacon is such infrastructure, that hooks into Redux and lets you map actions to analytics events as one-to-one or even fan-out (report to many analytics providers). You can use one of many ready-made integrations including Google Analytics and Segment.io and build your own.

redux-beacon-electron is a library that includes a customized Electron-friendly Google Analytics target, an opinionated Redux Beacon event mapper and an action tracker that will help you build a simple and maintainable analytics solution.

Quick Start

Set up your Redux Beacon infrastructure as you would normally. Then, install redux-beacon-electron:

$ yarn add redux-beacon-electron

Integrate your Electron app with Redux Beacon and redux-beacon-electron

You can provide your UA tracking identifier verbatim or pull it from configuration — initialization is done on the spot (and not through injecting the generic GA snippet into the DOM like many libraries do), and even more — you can initialize as many targets as you like (!), so if you want to report different areas of your app to different accounts you most definitely can.

Then, somewhere in your Redux actions (I’m using redux-actions but it doesn't really matter if you use something else):

The onMounted action will generate a page view that's no different to Google Analytics than any other website page view, which is what we want in order to get these events through (otherwise Google Analytics will be happy to drop non-conforming events silently). It will do the smart thing regarding page name, based on your Redux event - in this case it will split (based on "/") the action type and use "settings" as the page name.

The setMuteState action will emit an event hit to Google Analytics, and it too will break up the namespace into an "app" category and a "SET MUTE STATE" action.

Meta Events Mapper

You can use the actionMetaEventMapper if you believe (as I do) that actions should say how they map themselves to analytics events (as opposed to having a big switch case or mapping dictionary in a centralized place).

This means that the form of a Flux Standard Action that is tracked is now:

{
    type:...,
    action: ...,
    meta: {
        track: action=>({hit: "event"|"pageview", category, action, label, value})
    }
}

One Last Thing

A nice side effect to this approach is that you have end-to-end debuggability: Redux action -> Event -> network fetch call.

Actions and events:

Network:

For more information and pull requests see https://github.com/jondot/redux-beacon-electron