Getting Started with Event Instrumentation
Overview
NewsKit components are built to emit events "out of the box" via the provided NewsKit event instrumentation system. This system requires a small amount of setup in your project to allow the emitted events to reach your desired tag manager. Events fired via the provided instrumentation system can be forwarded to as many "handlers" as desired. NewsKit provides two handlers; a console handler which outputs the fired events to the browser console, and a Tealium handler which forwards the event onto the Tealium tag manager (Tealium must be present on the page for this handler to work). You can also create your own handlers, for example if you require forwarding events to a different tag manager.
As well as the above handlers, NewsKit also provided a middleware composition system to allow for operations on events before they reach a handler. For example, if you wanted to filter events to forward only a specific set to a tag manager, perform some event data transformations, or batch the events reaching a handler.
For more information, users with the relevant access can read the internal RFC which lead to this implementation. This can be found on GitHub.
Setup
The event instrumentation system is part of NewsKit, so the same regular install you have for other components is sufficient. The first step is to create the event instrumentation by calling the function; createEventInstrumentation
. This function takes two arguments;
- an array of event handler functions; an event handler function simply takes an array of events and returns the same. There are two handlers provided by NewsKit, a console and Tealium handler (exported under
instrumentationHandlers
), but you can also pass your own custom handlers. - an event context object; this is an optional, but recommended, object of contextual data relevant to the page the events are being fired from. It might contain for example the page url and a user identifier.
This function will return an object containing the context passed to it and the fireEvent
function. This is the function which is used internally by the NewsKit components to fire events to your handlers.
InstrumentationProvider
Similar to the way you may use the ThemeProvider to set the components theme, NewsKit provides a React context component called InstrumentationProvider
to wrap the React DOM of your project and provide the required event instrumentation down to NewsKit components. The props required for this component match the object output from the createEventInstrumentation
function and as a result, the object can simply be destructured into the props of the provider.
In this example the Link component, and any other NewsKit instrumentation enabled components would emit events to the browsers console. This could look something like this:
{
"originator": "link",
"trigger": "click",
"context": {
"url": "www.my-amazing-website.com"
}
}
InstrumentationProvider components can be nested if you wish to extend the context object to add extra data. See the relevant section below for more information and examples.
Middleware
NewsKit also contains a middleware composition system to allow for operations on events before they reach a handler. For example, if you wanted to filter events to forward only a specific set to a tag manager, perform some event data transformations, or batch the events reaching a handler. Instrumentation middleware functions have the same signature as handlers; they take in an array of events and must return an array of events. The returned array can be a different length or even empty if necessary, though it is recommended that middleware functions are pure and do not mutate the array or events.
In the example below, filter middleware is used to pass only specific events to specific handlers.
Custom Event Firing
You should not need to add any instrumentation event firing to NewsKit components as this is already provided, but there may be a case where you have pre-existing custom components and wish to utilise the single NewsKit event instrumentation. This can be done easily via two ways;
- using the NewsKit HOC
withInstrumentation
. This will wrap the component argument in the instrumentation context and afireEvent
prop will be passed to the component. - using the NewsKit React hook
useInstrumentation
. This will return an object containing thefireEvent
function.
You can then call this function with your custom instrumentation event as necessary, so long as it meets event requirements. Event objects must contain an event originator
(the name of the component firing the event) and an event trigger
from the EventTrigger
enum listed below (this can be used as a JS object or the direct string values in non-TS projects). Events can also contain a context
object, which can be any JSON-serializable structure.
Key | Value |
---|---|
Click | click |
Swipe | swipe |
Load | load |
Start | start |
Stop | stop |
End | end |
Pulse | pulse |
Nested Instrumentation Providers & Contexts
It is possible to build up and extend an events context by nesting instances of the InstrumentationProvider
. Each provider can take a context object which will be shallow merged onto the parent when an event is fired.
This can be useful to build up event information which is specific to a particular component instance, without that component needing to know anything outside its own scope. For example, a button can fire a click event, but the layers of context can provide the information on what the button is for and where it is on the page.
In this example we have a root InstrumentationProvider
providing the page url. Inside the Rail
component we have another InstrumentationProvider
; this provides any child events with rail specifics, like the rail name. The RailItem
then contains a button which fires a click event. The resulting click event would look like this:
{
"context": {
"pageUrl": "www.my-amazing-website.com",
"pageArea": "rail",
"railName": "Some great rail"
},
"originator": "button",
"trigger": "click"
}
It is important to remember that in the example above, the fireEvent
function is scoped to the context of the parent provider (the one which wraps the RailItem
). This means if we wanted to add more context to the event inside the RailItem
, in the example above, doing the following would NOT work as expected. The railItemId
we are adding to the context would NOT appear on the event context.
Instead, we can add context to the event directly (or we must put the button into a separate component and get the fireEvent
function at that scope level). Passing context information via the fireEvent function is the simpler of the two options:
This would produce the following event (for rail item 1) as expected:
{
"context": {
"pageUrl": "www.my-amazing-website.com",
"pageArea": "rail",
"railName": "Some great rail",
"railItemId": 1
},
"originator": "button",
"trigger": "click"
}