How we got Google analytics working for ember single page applications
Bob Gally wanted to know a little more about the people who visited his app—it was his store after all.
He’d just begun an e-commerce venture. An all-organic food products retailer with an environment-friendly supply chain–electric bikes for longer trips, bicycles for short rides, and pick-up points across the city for ad-hoc, emergency demands. His delivery boys wore caps emblazoned with the words We have Only One Home—Planet Earth.
It was a decent start at a time the world was turning topsy-turvy, because of an itsy-bitsy virus. Bob was moving ahead in sales; the inventory was on a tight leash, inquiries were picking up, and his delivery boys were an energetic bunch—the work-while-you-work, play-while-you-play type. Even though all went well, questions of a certain type nagged Bob at the back of his mind: Who were his customers? How many of them liked him, but found him pricey? How many found his cheese taxing on the digestive tracts? What was the reaction to his Bring-your-own-milk-bottles campaign? Should he hold a customer town hall? The kind held by these fancy automotive start-ups that serve them beer and ask them how the Android dashboard looked?
“This is the problem with this app, you know,” he told his wife, a feisty helper at the kitchens and a stern watcher of the till. “You never know… You never know…”
For hundreds of small-time entrepreneurs like Bob, going down the depths of digital could be bamboozling. During the good ol’ analogue days (In Bob’s case, physical retail), he’d know right away what was on the mind of his customers — he’d just sit down outside the store and ask them right away: ‘Why didn’t you drop by for Bob’s Broccoli?”
Now, he is serving a much wider market that is at once lucrative but shrouded in darkness. His customers were so hard.
“What I need is numbers and stuff. You know.. some graphs and deductions about the action taking place on the app..” he told the engineer who designed it. And that’s when a full block of gobbledegook hit him: ‘Single-page applications… Google Analytics not possible… frontend analytics are a tough nut…” His wife saw him cut the call in slow motion, with a look that suggested he’d been through the eye of a storm.
Oftentimes, there is no bridge between the engineer’s mindspace and the preoccupations of an entrepreneur, for whom products are just a means to an end, not a trophy. The end being solving a genuine customer need. For product engineers, it’s about creating a system that delivers the best with the available resources. Many a time, these aspirations don’t converge.
But great products have that bridge—not built overnight but overtime through a process called the Build-Measure-Learn loop. The back-end works like a silent machine with an unblinkered focus on improving the experience at the front, provided there is pure data about the action at the user’s end.
Much to the relief of people like Bob, software development has gone through a change: it’s now a part of accepted DevOps philosophy to measure what is built, and thus learn. Not just at Freshworks, product thinkers everywhere want to listen; to know where users stumble, where it’s all a breeze, and where they drop off the website.
This blog tells the story of how we at Freshworks engineered the outcome of enabling Google Analytics for Single-page apps. For people like Bob, it takes them closer to their customers.
A team or organization’s effectiveness is determined by its ability to:
- Ideate and quickly build a minimum viable product of that idea
- Measure its effectiveness in the market
- Learn from the process
- If required, repeat the process from step 1 with the new inputs
Backend analytics is an oft-trodden route, with tools like NewRelic providing detailed insights about performance and resource utilization in applications; backend analytics have a handicap though — they are more developer/ops centered. The sought-after metrics lie at the user end. Basically, the need of the hour was a strong analytics arm for Single-Page Applications.
Where’s the catch:
In traditional websites, it was easy to track the loading of new pages. The Google Analytics tag works like a charm in the good ol’ websites because the code snippet is run every time a new page loads. This goes for a toss in the Single-Page Applications (SPAs) that are being used widely these days. In SPAs, loading of new content is hard to track. In SPAs like our ember applications, the entire application – all resources including pages – are loaded in one go. As users click links on the app, new content is loaded dynamically without making page requests on the network. Google Analytics is stumped by the abject absence of page requests on the network. To make Google Analytics work with Ember, how do we smartly use the Google Analytics API to inform about page changes?
Google Analytics, with its simple-to-use Javascript library was a great fit, but, thinking ahead, we wanted to ensure continuity if we were to switch to other providers such as Heap or Mixpanel to track analytics. We didn’t want to land ourselves with integration reimplementation. Thankfully, an Ember addon did the trick. It allowed us to connect with Google Analytics, Mixpanel, Segment, etc. Writing an adapter for Heap is simple, too. The addon is called ember-metrics.
From Ember-metric’s GitHub page:
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.
Implementation:
Install the addon using Ember
ember install ember-metrics
Configure the addon
In frontend/config/environment.js add the following to the ENV object
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | metricsAdapters: [ { name: 'GoogleAnalytics' , environments: [ 'development' , 'production' , 'staging' ], config: { id: 'UA-XXXXXXXXX-X' , // 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: [''] } } ], |
While you’re at it, ensure the following is done:
- Provide your Google Analytics property ID in the id key.
- In the above settings, if the environment is development, then the debug version of Google Analytics JS is loaded. Extensive verbose messages are printed in the console for debugging purposes. If you do not require this, change this behavior by modifying the debug and trace keys
- The environments key determines in which environments Google Analytics is enabled. Note that if you have created your own custom environment names, you need to use them here. If everything works out, you would have only production listed here.
Base Analytics
Bob is now privy to a whole lot of information. He is now exposed to several doors into the mindspace of the customer. The following metrics can be analyzed with base analytics, whose implementation we will discuss in this section:
- Real-time view of usage
- Active users
- User languages
- User countries
- User behavior
- User engagement
- User browsers
- User OS
- User devices
- User flow through application
- Usage heat map over day of week and time
Cracking it!
Can the router be modified to track “routes/views” and make that as the monitor for page transitions? We tried that. Instead of adding stubs to every route, we addressed it at the router level with didTransition. Every time a transition is made, the information gets sent to Google Analytics as though a page was navigated. Voila! It captured all the information in one place. The trackPage API of the addon ember-metric is used here.
The changes are given effect by modifying frontend/app/router.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | const FB_ROUTER = Router.extend({ location: config.locationType, init() { this ._super(...arguments); }, metrics: service(), didTransition() { this ._super(...arguments); this ._trackPage(); }, _trackPage() { run.scheduleOnce( 'afterRender' , this , () => { let page = this .currentPath; let title = getWithDefault( this , 'currentRouteName' , 'unknown' ); get( this , 'metrics' ).trackPage({ page, title }); }); } }); |
And that’s it! You will be able to see some rich data in the Google Analytics console. Needless to say, the Page Views and Average Time on Page are the kind of actionable analytics anyone would want. Here we present a sample of how things will look if one were to run the Google Analytics console for Single Page applications.
Summary metrics
Metrics for a ‘Page’
Metrics for ‘browsers’
Metrics for detailed versions of MS Edge Browser
View of metrics for ‘Usage time and day of week’
Going beyond Page tracking
Bob should now have a great view of what’s happening at his digital storefront. He is delighted. As is the norm today, Bob is looking at a Big-Bang sale on his website. He is kicked about it.
For a scenario like this, analytics can play a big role in post-sale judgment of how the event went: which models sold like hot cakes and which shelves were left untouched.
Enter event tracking.
Events are a powerful feature in Google Analytics to track and measure custom events or ‘happenings’ in web applications.
Here’s an excerpt from Google Analytics documentation:
Events are user interactions with content that can be measured independently from a web page or a screen load. Downloads, mobile ad clicks, gadgets, Flash elements, AJAX embedded elements, and video plays are all examples of actions you might want to measure as Events.
As an example, we decided to test this out to see how many users clicked on one of our features sprint insights. To do this, we use the addon ember-metrics’s API trackEvent.
Inside the insights/sprint component, we used the didInsertElement function/hook to send the event. Whenever a user clicks on the sprint insights button (and the sprint insight component was inserted in the DOM) the ember-metrics‘s API trackEvent is called.
1 2 3 4 5 6 7 8 | metrics: service(), didInsertElement() { get( this , 'metrics' ).trackEvent( 'GoogleAnalytics' , { category: 'ui-interaction' , action: 'saw-insights' , label: 'Saw Insights' }); } |
With the above code in place, Bob is presented a dashboard of rich insights about the frontend of his application, about how his features were used. Below, we give you a peek into how Bob is able to get data about user behavior on his website. The following are sample reports.
View of all ‘saw-insights’ event
‘Saw-insights’ event drilled with ‘customer domain’
‘Saw-insights’ event drilled with ‘page accessed from’
‘Saw-insights’ event drilled with ‘weekday’
‘Behavior flow for saw-insights’ event
By just adding a few lines of code, a wealth of information about product metrics is unlocked. For products that haven’t implemented analytics yet, free and emerging ones and those trying to reduce costs, Google Analytics is a very viable and real option. Also, the free version is quite liberal, especially for smaller products, with 10 million hits per month and 500 hits per user session limits.
And one more thing, Bob has a paid Google 360 account, meaning he can move products with Google Analytics to the paid, unrestricted version if required.
The product-engineering dynamic
For Freshworks, the Bobs among us are very important. Entrepreneurs are tireless triers, and they become entrepreneurs to address real problems with solutions that are, clearly, not the right ones in the first place. But they try. Through trial, error and a whole lot of tinkering, they get there eventually. It’s our mission to help them in that journey to solve real problems.
The other takeaway is a little more personal for Freshworks, if we can use that word for an enterprise. Analytics exposes engineers to a whole lot of customer insight that helps them understand why people from Product want things a certain way—because the customers like it that way. This connection, this bridge is what Freshworks wants at home: Engineering and Product working like twin engines of the perfect airplane, always in sync but at arm’s length to ensure autonomy.
Here’s how Arun Venkataswamy, a two-time entrepreneur now an Engineering Leader at Freshworks , put it across to me: At Freshworks, the kind of product, and the ‘why’ and ‘what’ we develop are clearly in the domain of the product team. However, decisions on ‘how’ to build them are in the domain of the engineering team. After many days of development and release, proper insights and visibility might reveal that the customer is simply not using the product feature the way it was intended. This might lead the product team to approach Engineering again for changes. Sometimes, months of work may need to be reworked or worse, ditched. When that happens, engineers get peeved.
But, here’s the thing about engineers: they never mistrust data. When they are presented with the “why” of it, along with the data, they get closer to the customer and understand the Big Picture.