MutationObserver Playground

MutationObserver watches a DOM node and fires a callback with a batch of MutationRecords whenever it changes — no polling required. Toggle the observer config below, poke the sandbox, and watch the records roll in.

// 1. observer config

at least one of childList / attributes / characterData must be on — observer paused

// 2. dom sandbox

// 3. mutation log

records: 0
No mutations yet. Poke the sandbox above.

// 4. practical example: stop polling for third-party widgets

The classic use case: a chat widget, ad slot, or analytics script injects markup after your code runs. Instead of a setInterval poll, observe and react the moment it lands:

// polling: wasteful, races with the widget
const timer = setInterval(() => {
  const el = document.querySelector('#chat-widget');
  if (el) { clearInterval(timer); initWidget(el); }
}, 250);

// observer: exact, zero wasted work
const obs = new MutationObserver((records) => {
  for (const m of records) {
    for (const n of m.addedNodes) {
      if (n.id === 'chat-widget') { obs.disconnect(); initWidget(n); }
    }
  }
});
obs.observe(document.body, { childList: true, subtree: true });

One caution: subtree: true on a huge root like document.body watches everything. Always observe the narrowest node that contains what you care about.