Skip to main content
Skip table of contents

Element Visibility Tracking and Mutation Observers

In today's digital era, data drives decisions. Websites, serving as dynamic interaction platforms, must efficiently capture user interactions and behavioral data to optimize user experiences and enhance business strategies. In this article we provide a pragmatic solution that enables advanced tracking on elements that pop up dynamically in a website. This approach allows businesses to tailor data collection mechanisms to their specific needs, capturing the nuances of user interactions with unprecedented accuracy.

Goal - Observe Changes in your Websites Document Object Model (DOM)

The primary goal of integrating custom code for data capturing on websites is to obtain detailed, actionable insights into how users interact with various elements of the site. By leveraging these insights, businesses can make informed decisions to improve user engagement, increase conversions, and optimize the overall user experience. Custom code implementations, such as Mutation Observers in JavaScript, play a crucial role in achieving this goal by monitoring changes to the DOM (Document Object Model) in real-time, thus ensuring that every significant interaction is captured.

Challenges of Using Mutation Observers

While Mutation Observers are powerful for tracking dynamic changes on web pages, their use comes with several challenges:

1. Performance Impact

  • Resource Intensive: Mutation Observers can be resource-intensive, especially if not implemented correctly. Observing a large part of the DOM or monitoring a wide array of mutations (attributes, childList, and subtree) can lead to significant performance degradation.

  • Redundant Triggers: Inefficient selectors or broad observation scopes can cause the observer to trigger too many times, processing a large amount of unnecessary data and adversely affecting website performance.

2. Complexity in Configuration

  • Setup Complexity: Configuring Mutation Observers requires a deep understanding of both the targeted DOM elements and the types of changes that are relevant. Misconfigurations can lead to missed data or excessive, irrelevant data capture.

  • Dynamic Content Handling: Websites with highly dynamic content, where elements are frequently added, removed, or modified, pose additional challenges in ensuring that observers are correctly attached and detached as the DOM evolves.

3. Data Overload

  • High Volume of Data: Without precise targeting and filtering, Mutation Observers can generate a vast amount of data, potentially overwhelming the data processing pipeline and leading to inefficiencies in data handling and storage.

Overcome the Caveats and Challenges with Custom Code

Given the outlined challenges you must make sure to test your custom configuration extensively. Only when the CSS selectors are granular enough and catch only relevant elements your configuration should pass and go live.

Within the following code solution we provide configurations to make the observer as elegant and less intrusive as possible.

Configuration options:

  • selector: use a valid CSS selector to identify the element that became visible on your website.

  • event_group and event_name: this code will push a JENTIS event with the given properties, so you can create triggers based on the “JENTIS datalayer State” and conditions looking for your specific group and name values.

  • track_once: use “true” to only track an element once, this will improve and help to fool-proof the code, so it is not tracking and observing any changes after it activated once.

Here is the code that you can copy-paste to your JENTIS Data Capturing platform in “Code” sections.

(in the example we have two selector configurations with according event_group and event_name, you can define as many configurations as you need)

JS
// add here CSS selector strings and event group+name to be tracked with _jts events (native JENTIS Data Layer)
let configArray = [{ 
      selector    : '#li24',
      event_group : 'element_visibility',
      event_name  : 'list_item_added',
      track_once  : true //remove observer when found once; set "false" for multiple observations
    },{ 
      selector    : '#li25',
      event_group : 'element_visibility',
      event_name  : 'list_item25_added',
      track_once  : false //remove observer when found once; set "false" for multiple observations
    }
    //,{ selector: '.element2', event_group:'', event_name: 'event2' },
    // Add more objects as needed
];

const observer = new MutationObserver((mutationsList, observer) => {
    mutationsList.forEach((mutation) => {
        if (mutation.type === 'childList') {
            // Check added nodes to see if they include the element of interest                          
            mutation.addedNodes.forEach((node) => {
              if (node.nodeType === Node.ELEMENT_NODE) { // Ensure node is an element
                configArray.forEach((item) => {
                  if (node.matches(item.selector) || node.querySelector(item.selector)) {
                    _jts.push({
                          "track"    : "event",
                          "group"    : item.event_group,
                          "name"     : item.event_name,
                          "observer" : "childList"
                        });
                    if(item.track_once)
                    configArray = configArray.filter(con_item => !(item.event_group === con_item.event_group && 
                                                                   item.event_name  === con_item.event_name));
                  
                  }
                });
              }
            });
        }
        if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
            // Directly target the mutated element
            const targetElement = mutation.target;
            configArray.forEach((item) => {
                if (targetElement.matches(item.selector) && targetElement.offsetParent !== null) {
                    _jts.push({
                        "track"    : "event",
                        "group"    : item.event_group,
                        "name"     : item.event_name,
                        "observer" : "attributes"
                    });
                    if (item.track_once) {
                        configArray = configArray.filter(con_item => !(item.event_group === con_item.event_group &&
                                                                       item.event_name  === con_item.event_name));
                    }
                }
            });
        }
    });
});

// Start observing mutations in the entire document
observer.observe(document, { childList: true, attributes: true, subtree: true });

Conclusion

Mutation Observers offer a powerful method for custom data tracking on websites. However, their implementation must be carefully planned and continuously monitored to harness their full potential without compromising website performance. By addressing the challenges and adhering to best practices, businesses can effectively leverage JENTIS's capabilities to enhance their data capturing strategies, leading to better data-driven decisions and optimized user experiences.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.