Why Objectiv captures the logical structure of your product inside your dataset

Bob Jansen

As part of our mission to enable effective data science in the product analytics workflow, we’ve completely redesigned the analytics tracker from scratch. One of its unique features is the ability to capture exactly where in your product an event was triggered. This information is stored in the event itself. Today, we want to show you how that works and why it matters.

Why capture the event’s UI location?

To demonstrate why that’s useful, let’s take a look at a typical event that you would get from Google Analytics:

  ec: link
ea: click
el: overview

This fictional event relates to users clicking this link in our Docs:

A click on 'Overview' in the DataFrame section of the API reference

A click on 'Overview' in the DataFrame section of the API reference

Now, with just the raw data to go by, you would have a hard time identifying exactly where this event came from. You would need to have access to the source code and UI of the exact version this event was collected from.

This is an inconvenience at best, but becomes problematic when your product has undergone changes over time as a result of new releases, experiments, A/B tests etcetera. Figuring out what happened in your product a month ago based on a collection of ambiguous events that no longer match up with your current instrumentation can be pretty painful.

Bring your Sherlock game

Bring your Sherlock game

It’s also impossible to quickly select all the events that came from a specific logical part of your product (i.e. the side bar in this example) without finding and mapping all the events belonging to that section first.

How Objectiv handles events

Here is an example of the same event, but this time collected by Objectiv’s tracker:

"_type": "PressEvent",
"location_stack": [
"_type": "RootLocationContext",
"id": "modeling"
"_type": "NavigationContext",
"id": "docs-sidebar"
"_type": "ExpandableContext",
"id": "api-reference"
"_type": "ExpandableContext",
"id": "dataframe"
"_type": "LinkContext",
"id": "overview",
"href": "https://objectiv.io/docs/modeling/bach/api-reference/DataFrame/"

The Objectiv tracker captures the exact location where the event was triggered in a hierarchical stack of sections, called the Location Stack. As you can tell from this example event, you don’t need any other reference to be able to identify where it came from.

This also holds true if your product has changed over time, as the logical structure of your product is captured in the event itself at the time of collection.

So, where do ‘Location Stacks’ come from?

Location stacks are generated by the tracker, based on a logical mapping that has been added to your product during instrumentation.

We ask the front-end developer to instrument the interactions (e.g. clicks on links), and then enrich the Locations of events by mapping the logical UI sections of the product (e.g. navigation bar, header, main, footer). By using predefined events and locations from the Open Analytics Taxonomy, the dataset you collect will become compatible with any model that embraces it.

Locations can be nested to build a logical model into your product that the tracker uses to identify exactly where events are triggered:

import { TrackedNav, TrackedAnchor } from "@objectiv/tracker-react";
import TrackedSideBarCategory from './components/sidebar-category';

export default function sidebarMenu() {
return (
<TrackedNav id={'docs-sidebar'}>
<TrackedSideBarCategory text='API Reference'>
<TrackedSideBarCategory text='DataFrame'>
<TrackedAnchor href="/docs/modeling/bach/api-reference/DataFrame/">

This example shows you how you can use wrapped components to map logical UI sections for a React-based application, such as our Docs.

Wherever possible, Objectiv tries to automatically generate the IDs based on the attributes of the element that’s being tracked. Objectiv also supports other platforms and frameworks. Check out our docs for more information.

While this approach requires a bit more work to set up, capturing this hierarchical stack of sections serves another important purpose: slicing.

Fine grained slicing control

As your dataset now carries the logical model of your product, you can use it to slice events on a very granular level without the need to do a ton of manual mapping first.

For the sake of demonstration, let’s assume we’re specifically interested in user behavior within all navigation elements. With our modeling library, you can get that from the data by running a single command from your Jupyter notebook:

location_stack.json[{ "_type": "NavigationContext"}:]

This results in a clean dataframe with all events generated inside any navigation component in your product. With that, you can straight on build further analyses.

Or say you want to look at user behavior on a more specific level, to look at interactions with just the sidebar navigation in the docs:

location_stack.json[{"id": "docs-sidebar", "_type": "NavigationContext"}:]


A third benefit of mapping the logical sections of your product is that it allows you to validate your instrumentation in real-time while you’re developing. We will discuss the topic of validation in an upcoming blog post.


So in short, by mapping the logical sections of your product in your instrumentation, you get:

  • Events that are much easier to identify without additional resources
  • Fine grained slicing control without manual mapping at model-time
  • Debuggable analytics instrumentation at compile-time

We hope you're as excited about our approach to event collection as we are. Give Objectiv a try and let us know what you think. For a quick rundown of what Objectiv can do, check out our 2 minute video below.

Try Objectiv

Get Objectiv Up - Try Objectiv on your local machine (takes 5 minutes)
Objectiv on GitHub - Check out the project and star us for future reference
Objectiv on Slack - Join the discussion or get help