In 2020 we can say that the modern web is incomplete without any analytics tracking. As we try to know our users better with a goal of creating more engaging and friendly experiences, we need to have data on their behavior. Every company has its own unique approach and after completing many successful projects that measured traffic and conversion in AEM world, we've also come to some conclusions, that can be shared.

Analytics workflow

Let's try to investigate the analytics implementation process in search of best practices that help us finish the process faster. How do we normally approach our implementation? We can divide it into these steps:

  1. Gathering requirements
  2. Preparing access and tag managers accounts
  3. Preparing the test suite and adding the test tracking code to our development code
  4. Implementing custom tracking
  5. Iterational testing and fixing the code and the tag manager setup.

After taking a closer look at those items, We've noticed that for starters it's great to have baseline tracking requirements prepared. This will be used as a starting point for our design. Information can be gathered while comparing previous SDRs (Solution Design Reference) - in most of the cases it is easy to spot repeating data like page name/ URL, domain, language, etc for page views. We didn't really find a way to speed up the second step, yet the third and fourth ones are where the most valuable findings are.

3rd Party Code

Code image - Creative commons from

In 2019/2020 it's common practice to use different tag managers as a tracking code proxy. It's practical, eases the integration process and allows non-developer analysts to add base tracking devices. In AEM world we often use Launch /Adobe Analytics as a tag manager for our metrics. Even though Experience Managers has an out-of-the-box integration mechanism, after a closer look it's not the best approach for us:

  • There is no easy way to use test/development suites on our pre-production environments
  • It's complex (multi-step configuration) and cannot be easily shared between environments
  • It requires author instances to be able to access Launch servers (the problem lies in secured-by-isolation instance setup)
  • This only supports Adobe Launch

So in case of projects with big, secured infrastructures, this will cause some problems with setup and maintenance. Crossing out the out-of-the-box integration, we are left with the direct tag manager code injection. What is the best way to do that? The simplest case is to put the code directly in the page jsp/html in the code repository. It's not either elegant or pleasant when it has to be updated often. What if we want to make the third party code also configurable or it has multiple variants depending on the environment? One way is the OSGi configuration - component can easily populate our pages code with the required tag manager. However this way only OSGi-enabled users can change it, and the goal of easily sharing the config between environments is still there (Should the configuration be placed in project repository? If so there is a chance they are overwritten every time the new version is deployed. If that's expected - without rising the bundle version we don't have the certainty it's gonna happen).

It leaves us with the last viable option - let's put it as a part of a content (As Sling creed states: Everything is content!). Let's create a configuration page that will allow us to set the header code. This also can be extracted and reused between other projects. This way we have a consistent approach that will support different types of tag managers in our projects.


When we think about the structure, we need to take into consideration the possibility of configuring multiple markets. For example, English and German markets could have not only different tag managers suites introduced - they could use totally different tag managers in extreme cases.


The configuration we design should support adding 3rd party code snippets. Such structure:

  • Head Code
  • Top of the body tag code
  • Bottom of the body tag code

enabled us to cover all of the most important page load events.

At this level, we've come up with another improvement that enables easier integration with different tag managers - event functions mapping. The basic idea of tracking is to catch different types of events and actions: Page loads and dynamic page actions. First is pretty straightforward, it enables counting the unique visits, overall traffic, hot spots in our content tree, etc. Second is about tracking specific actions like downloading the files, using CTAs, navigation preferences, and most important catching data about the conversion - actions connected with crucial functionality of our pages e.g. e-commerce shopping, promotion material downloads, subscribing to feeds, etc. As tag managers can track those in different ways (separate api functions, automatic page loads), we added ability to define globally available page load function and similar custom action function. With that, we are achieving abstraction allowing our implementations to be independent of used tag manager. Imagine that base code calling the custom tracking the pdf link is just the same across any project, mapping function takes care of using the right api call of the tag manager used.


With all the above steps taken, there is a number of gains:

  • A standardized way for implementing analytics for all your projects
  • Your implementation is independent of the tag manager
  • Faster time to market with reused base code applied to new projects.
  • Analytics configurations as a content that can be versioned and easily deployed to different environments.

Hopefully, after reading this short article, you can also use some of the above hints in different applications other than analytics.