Sign in
Log inSign up
How to track changes in the DOM using Mutation Observer

How to track changes in the DOM using Mutation Observer

SessionStack's photo
SessionStack
·Jun 2, 2017

What is MutationObserver?

MutationObserver is a Web API provided by modern browsers for detecting changes in the DOM. With this API one can listen to newly added or removed nodes, attribute changes or changes in the text content of text nodes.

Why would you want to do that?

There are quite a few cases in which MutationObserver API can come really handy. For instance, you might be working on a WYSIWYG editor, trying to implement undo/redo functionality. By leveraging the MutationObserver API, you know at any given point what changes have been made, so you can easily undo them. Or let’s say you want to notify your web app visitor that some change has occurred on the page he’s currently on. Another example: you’re working on a new fancy JavaScript framework that loads dynamically JavaScript modules based on how the DOM changes. These are just a few examples of how the MutationObserver can be of help.

Alternatives

The MutationObserver, however, has not always been around. So what did developers resort to before the MutationObserver came along? The simplest and most unsophisticated way was by polling. Using the browser setInterval WebAPI you can set up a task that would periodically check if any changes occurred. Naturally, this method significantly degraded web app/website performance.

In the year 2000, the MutationEvents API was introduced. Albeit useful, mutation events are fired on every single change in the DOM which again causes performance issues. Nowadays the MutationEvents API has been deprecated, and soon modern browsers will stop supporting it altogether.

A somewhat strange alternative is a one that relies on CSS animations. It might sound a bit confusing. Basically, the idea is to create an animation which would be triggered once an element has been added to the DOM. The moment the animation starts, the animationstart event will be fired: if you have attached an event handler to that event, you’d know exactly when the element has been added to the DOM. The animation’s execution time period should be so small that it’s practically invisible to the user. You can check out David Walsh’s blog post for more details on its implementation.

MutationObserver offers a number of advantages over the above-mentioned solutions. In essence, it covers every single change that can possibly occur in the DOM and it’s way more optimized as it fires the changes in batches. On top of it, MutationObserver is supported by all modern major browsers, along with a couple of polyfills which use MutationEvents under the hood.

How to use MutationObserver

Implementing MutationObserver into your app is rather easy. You need to create a MutationObserver instance by passing it a function that would be called every time a mutation has occurred. The first argument of the function is a collection of all mutations which have occurred in a single batch. Each mutation provides information about its type and the changes which have occurred.

var mutationObserver = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
              console.log(mutation);
        });
});

The created object has three methods:

  • observer – starts listening for changes. Takes two arguments – the DOM node you want to observe and a settings object.
  • disconnect – stops listening for changes
  • takeRecords – returns the last batch of changes before the callback has been fired
// Starts listening for changes in the root HTML element of the page.
mutationObserver.observe(document.documentElement, {
    attributes: true,
    characterData: true,
    childList: true,
    subtree: true,
    attributeOldValue: true,
    characterDataOldValue: true
});
// Takes all changes which haven’t been fired so far.
var changes = mutationObserver.takeRecords();

// Stops the MutationObserver from listening for changes.
mutationObserver.disconnect();

MutationObserver occupies a central position in SessionStack. SessionStack doesn’t record an actual video but is rather listening for the changes in the website/web app. Later on, these changes will be recreated in a sandboxed environment which results in the session being replayed just like an ordinary video. The difference is that it’s way lighter than a recorded video, both in terms of CPU and network traffic.

Getting ever more popular, MutationObserver is a really useful tool that can have various use cases. Certainly a great addition to the web developer’s toolbox!

This post was originally shared on the SessionStack blog.