About Us

An opinionated tracking design

Data-informed decisions are at the very core of how we do product at Capmo.

We strive to serve our customers better, identifying flaws in our app flows, and paying close attention to how they interact with the features.

In order to assert and analyze how our customers use our apps, we needed a homogenous tracking approach for both our mobile and web apps.

The basic concept

Traditional tracking approaches are based on the concept of a tracking event being fired as soon as users interact with the app. Every interaction is susceptible to being a single action event, e.g. hitting a button, or opening a new view.

This approach places focus on the selected tracking tool and its ability to derive useful information from those single events.

We at Capmo, decided to implement the tracking logic on the clients, assembling relevant information and appending it to our tracking events before sending them to our tool of choice.

The anatomy of a Tracking Event

Tracking events are the base unit of our tracking design. They contain a name and a set of properties, such as duration, source, and any other event-specific information we are interested in tracking.

TrackingEvent {
name: String
properties: [String : Any]

Types of events

Tracking events are divided in two major categories: page impressions (PI, from now on) and single action events. Under the latter category, we would usually find events originating from user interactions, e.g. click/tap events, toggle of a switch, etc.

Page Impressions (PI)

This is the juicy part and arguably the one that brings us, engineers, the most headaches.

A PI is an event that starts being tracked the moment a user walks into a view context. From that moment we set a timestamp. User interaction on that view is tracked and, once the user leaves it, the event is sent to our tracking service containing the compiled state of all user interactions in that specific context, and the time the user spent on it.

Most of our views have an associated PI event.

This approach helps us build an understanding of how long users interact with a view and whether they struggle or not on specific steps of our flows.

A challenge in the implementation

On paper, that approach seems quite straightforward. There is a catch, though.

Modern mobile UI frameworks like SwiftUI or Jetpack Compose, rely on the basic concept that UI is rendered based on state. A given screen could be rendered multiple times based on state changes.

As stated above, our tracking events are long-lasting. So knowing out of those multiple rendering actions which one was the first to fire the tracking starting pistol becomes kind of tricky and it’s, technically, working against the system.

Our current approach on iOS

Our new mobile app is being built using mainly SwiftUI. As much as we love the framework, we are mindful of its current limitations. Navigation is probably one of the major construction sites.

Stepping back there and using UIKit for all navigation purposes helped us to tackle the tracking problem, as well as many others related to the coupling of views.

UIKit gives us total power on the view lifecycle (viewDidLoad, viewWillAppear, viewDidAppear, viewWillDisappear, viewDidDisappear), simplifying our tracking handling as well.

Stay tuned to read more about how we leverage UIKit and SwiftUI together.

Thanks for reading! ✌️

Are you ready for a new challenge?

Join Capmo and make an impact!

Thousands of construction projects all over Europe are not digitised yet. Apply now and change one of the biggest industries worldwide!

Check out our open positions
Capmo employees at the gathering