🛤 redux-track
Ever wanted to track the state of your Redux-powered application without having to add a bunch of metadata to your actions? We did at Contiamo, and so I thought I'd build redux-track
.
If you're unfamiliar with Redux, I'd highly recommend reading up on it. It's a predictable state container for your apps: basically, it allows you to easily track and manage the state of your application.
It also allows you to put middlemen (read: middleware) between the thing that updates the state and the actual state update itself. That's what this is: when you say "HEY REDUX, UPDATE THE STATE!", this little piece of code is run just before Redux says "OK WILL DO THX".
This little piece of code runs a function that you give it in your action under the key reduxTrack
that handles the rest for you, since most tracker functions carry similar (if not the same) call signatures:
(name: string, payload: { [key: string]: any }) => void
.
Simple!
yarn add redux-track
- Apply the middleware to your redux store in similar fashion:
import { createStore, applyMiddleware } from "redux"
import { reduxTrack } from "redux-track"
import { rootReducer } from "./reducer"
export const myStore = createStore(rootReducer, applyMiddleware(reduxTrack))
Note: you probably have other middlewares going on. Redux Middleware is composable, so you can just add it on to a list if you need to.
- Find a Redux action/action creator that you'd like to track with your event tracker.
- Reference your event tracker's tracking function in a
reduxTrack
property on the action.
Fore more detailed instructions, see the case studies below.
So at Contiamo, we have our own really cool event tracker that we built in-house. It's fairly similar to others out there: you include a snippet in your HTML page before </body>
that registers a global at window.contiamo
, that you can track events with by invoking contiamo.event('name', { any: 'thing', can: 'go', in: 'here' })
, which is then sent to our platform.
To use this with redux-track
, we simply update one of our actions from our codebase, say one that handles pagination, to reference this function in a property called reduxTrack
. Concretely, here is what this looks like:
dispatch({
type: "GO_TO_PAGE",
page: 3,
})
dispatch({
type: "GO_TO_PAGE",
page: 3,
reduxTrack: contiamo.event,
})
and bam 💥 we have tracking. It is painless. The middleware invokes action.reduxTrack
with the same call signature as our tracker. Of course, you're welcome to roll your own function that adapts to this signature. Our research has show that most event trackers have fairly similar call signatures in their tracking functions.
This would send an event to our backend titled GO_TO_PAGE
, with the content of the Redux action, minus the type
and reduxTrack
properties: effectively giving us what happened and all relevant metadata at the time of dispatch.
But what if your event tracker has a different call signature? Well, read on.
Everyone uses Google Tag Manager to track stuff, right? It's so easy! They give you a snippet, and then an event tracker! So cool! Here's how it would work in a typical Redux app with redux-track
:
First, Add your tracking code to your webpage, it looks something like this:
<!-- Global Site Tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=GA_TRACKING_ID"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'GA_TRACKING_ID');
</script>
Then, to track events, invoke the global gtag
function as so:
gtag("event", "event_name", {
// Event parameters
parameter_1: "value_1",
parameter_2: "value_2",
// ...
})
This requires some fun coding, because gtag
's event tracker has a slightly different call signature: you need to tell it the type of event, and then the event name and relevant metadata.
For comparison,
This middleware expects:
(eventName: string, eventMetadata: {}) => void
Google Tag Manager gives you:
(hitType: string, eventName: string, eventMetadata: {}) => void
🤔 How can we solve this? Well, write an adapter as so:
const myEventTracker = function() {
return gtag("event", ...arguments)
}
From there, it's fairly simple: find an action creator in your code, or a dispatch call. It would typically look something like this:
function addTodo(text) {
return {
type: ADD_TODO,
text,
}
}
and reference this newly created function myEventTracker
in a reduxTrack
property as so:
function addTodo(text) {
return {
type: "ADD_TODO",
text,
reduxTrack: myEventTracker,
}
}
Simple! You now have your action(s) sending events to Google Tag Manager. Yay!
lol this is far from a perfect implementation of anything. I just made it to help one of our internal projects at Contiamo. I love collaboration. I love Pull Requests. Give me some! WOOOO! 🎉