How to track user interactions in your React app
Worry not about which Analytics provider you need to gather user interaction within your app.
Instead, worry more about how to gather these interactions.
A few months ago, I was involved in an Analytics project within a large E-commerce organization. This organization has a data-driven business where the analytics are more important than anything else.
We were building a Datalayer solution to hold all the user interactions and actions before pushing them to the Analytics provider (for example, Google Tag Manager). We built our DataLayer solution without having React in mind, as the migration to React started later.
React Time!
We started the migration to React progressively, which means React was responsible only for rendering some parts of the platform. And I was responsible for integrating the DataLayer solution we had already built with React Land.
Suddenly, the difficulties started coming up:
- The solution was jQuery based
- It was unpredictable
- It was hard to test and maintain
- Sharing knowledge with other developers who didn’t have analytics experience was scary!
I started looking in the community for ready-to-use solutions that fit our needs. There was just no chance.
And here’s where the idea of React-Tracker came in.
Why React-tracker?
- It’s easy to use, test, and maintain (Redux-like)
- It can be used with any Analytics provider
- It’s scalable and predictible
- It has a minimal API
With React-tracker, we were easily able to integrate two Analytics providers (Google Tag manager and Adobe Analytics).
How?
To keep it simple, think of it as Redux.
- Instantiate your Tracker ~ Store of your events
- Create your event-listener(s) ~ Reducer
- Event ~ Action
- Provide your tracker instance to your Root Component.
- React-tracker will magically take care of providing your tracker instance to all your Components.
Before instantiating anything, let’s go through each term on the list above and explain it.
What is Tracker?
A Tracker is a bag that holds the tracking-history along with some functions to listen to/dispatch events.
tracker.on(eventType, callback)
the given callback will be called whenever an event withevent.type
equal to the giveneventType
is dispatched.tracker.trackEvent(event)
is a function that accepts anevent
and calls all the event-listeners that listen on thisevent
.tracker.getHistory()
returns an Array and contains all the tracked events that were saved
What is an Event?
An event is a plain object that represents the user interaction, like user click, page view, and purchase.
It should be an object with type
and associated data
if any. Here’s an example of a PageView
event:
const PageViewEvent = {
type: 'PAGE_VIEW', // Required
data: { // Optional
pageId: '123',
userId: 'UID-123'
}
}
What is the Event-listener?
The event-listener is a function that will be called if its eventType
matched the type of the dispatched event.
eventListener.eventType === event.type
Example of an Event-listener:
const pageViewListener = (event,
) => {
// For example let's push the received event to our DataLayer.
window.dataLayer.push(event); return event;
};
Let’s allow our pageViewListener
to listen only on PAGE_VIEW
event:
pageViewListener.eventType = 'PAGE_VIEW';
There are four things to notice here:
- Returning the event will save it in the trackingHistory. Otherwise it will be ignored :)
- If no
eventType
was specified to the event-listener, it will be called on every event dispatch. eventHistory
was provided as a second parameter to help you apply restrictions on your events easily, like tracking a Product-click once. In order to achieve this, you need to have the history of events in your hands.- Pushing our event to
window.dataLayer
was just an example. You can mainly do anything in this function like callingGTM
directly orFacebook Pixel
Time to combine everything
First things first:
1. Instantiate our hero Tracker:
import { Tracker } from 'react-tracker';const tracker = new Tracker();
That’s it!
Now we have our Tracker
but with no event-listener :-(
There are two ways to add event-listeners to your Tracker
:
- On instantiating:
const anOtherTracker = new Tracker([
pageViewListener,
productClickListener,
...
]);
- Or you can add the event-listener after instantiating your
Tracker
usingon
:
const anOtherTracker = new Tracker();tracker.on('PAGE_VIEW', pageViewListener);
2. Create a page view event-listener :
I want my event-listener to push the received PAGE_VIEW
event directly to my dataLayer.
const pageViewListener = (event, trackingHistory) { window.dataLayer.push(event);};
Let our tracker
know about the pageViewListener
:
tracker.on('PAGE_VIEW', pageViewListener);
3. Create Event-creator :
Event-creator is just a function that returns an event object:
const pageViewEvent = (pageId, userId) => ({
type: 'PAGE_VIEW',
data: {
pageId,
userId
}
});
Our Tracker is well configured now.
Introducing our tracker
to React
4. Provide our tracker
to the Root Component:
import React from 'react;
import ReactDOM from 'react-dom';
import { TrackerProvider } from 'react-tracker'import RootComponent from '../RootComponent';const RootComponentWithTracking = (
<TrackerProvider tracker={tracker}>
<RootComponent />
</TrackerProvider>
);const domElement = document.getElementById('root');ReactDOM.render(<RootComponentWithTracking />, domElement);
By providing our tracker
to the root component, it will be magically available for all the sub-components.
So now, since we have our tracker
available, let’s use it to track the PAGE_VIEW
event on the RootComponent
mount.
4. Track Page View Event.
import React from 'react';
import { withTracking } from 'react-tracker';
// We created this function earlier at (3.)
import { pageViewEvent} from '../tracking/events';class RootComponent extends React.Component {
componentDidMount() {
this.props.trackPageView(this.props.pageId, this.props.userId)
} render() {
return (<h1> My App is awesome </h1>)
}
};const mapTrackingToProps = trackEvent => ({
trackPageView: (pageId, userId) =>
trackEvent(pageViewEvent(pageId, userId))
});export default withTracking(mapTrackingToProps)(RootComponent);
withTracking
HOC will take care of providing us trackEvent
from our tracker
so we can use it to track the pageView
event.
mapTrackingToProps
will merge the returned object with the RootComponent
’s props, which means the trackPageView
will be available as a prop within RootComponent.
That’s it — you’re done ;)
5. Demo
Please refer to this demo and to GitHub for in-depth documentation and a better way to organize your tracking files.
Give it a try!
React-tracker was built to facilitate the integration of Analytics tools as much as possible, by proving a minimal API and easy integration with your react app.
Thanks
Thank you doha faridi, AbdelAli Eramli and khalid benrafik for your helpful feedback.