Waiting for an Element to Exist
A small helper that solves 80% of timing bugs in client-side experiments.
Most variant bugs are timing bugs. The script runs before the element exists, the selector returns null, and the variant silently fails. The fix is a waitForElement helper that returns a promise resolving once the node appears.
The helper has three rules. First: check synchronously before observing — if the element is already there, do not waste a MutationObserver. Second: always disconnect the observer once you have the element. Third: include a timeout so a missing element does not leak observers indefinitely.
This single helper, written once and reused everywhere, eliminates an entire class of bug from your CRO codebase.
Example
function waitForElement(selector, { root = document.body, timeout = 8000 } = {}) {
return new Promise((resolve, reject) => {
const found = root.querySelector(selector);
if (found) return resolve(found);
const obs = new MutationObserver(() => {
const el = root.querySelector(selector);
if (el) { obs.disconnect(); resolve(el); }
});
obs.observe(root, { childList: true, subtree: true });
setTimeout(() => { obs.disconnect(); reject(new Error('Timeout: ' + selector)); }, timeout);
});
}Try this on the Shop
The best way to learn is to ship. Open this surface and apply the lesson.
See the Selector Wand