Open a fullscreen quiz after a delay or on exit intent
Goal: a product page carries a fullscreen quiz that stays out of the way, then opens after N seconds on the page or when the pointer heads for the tab bar, once per visit.
Uses: Storefront JS API, ready(), close(), open(), quiz.closed. Nothing to install; no API key. The methods work on every plan.
The container starts invisible, the API closes it, a trigger opens it
Section titled “The container starts invisible, the API closes it, a trigger opens it”A fullscreen quiz shows its overlay as soon as it mounts, and close() can only run once the quiz is mounted (ready). To avoid a flash between the two, hide the container with CSS first; close() then parks the overlay and restores the page’s scrolling, and the CSS comes off so a later open() shows it.
<!-- the container from the dashboard's snippet (Publish > Embed), with data-embed-type="fullscreen", an id and the style; keep the app.js script tag of that snippet after it --><div class="octane-ai-app" id="quiz-popup" data-app-id="7c9e6679-7425-40de-944b-e07fc1f90ae7" data-bot-id="5f3a2b1c9d8e7f6a5b4c3d2e" data-embed-type="fullscreen" style="visibility: hidden"></div><script> window.octaneai = window.octaneai || []; window.octaneai.push(function (octaneai) { var DELAY_MS = 20000; var SEEN_KEY = 'octane:popup-shown'; var container = document.getElementById('quiz-popup'); var opened = false;
function openOnce() { if (opened) return; opened = true; try { sessionStorage.setItem(SEEN_KEY, '1'); } catch (e) {} octaneai.open(); }
octaneai.ready(function (api) { api.close(); container.style.visibility = ''; var seen = false; try { seen = sessionStorage.getItem(SEEN_KEY) === '1'; } catch (e) {} if (seen) return;
setTimeout(openOnce, DELAY_MS); document.addEventListener('mouseout', function (e) { if (!e.relatedTarget && e.clientY <= 0) openOnce(); }); });
});</script>The mouseout check is the exit-intent signal on desktop: the pointer left the document through its top edge. Phones have no pointer; there the delay is the only trigger.
Errors to handle
Section titled “Errors to handle”open()andclose()before any quiz mounted log[OctaneAI] no quiz on this page yetand do nothing;ready()is what guarantees the quiz is there.sessionStoragethrows in some private modes; thetryblocks keep the popup working without the once-per-visit memory.
Things to know
Section titled “Things to know”close()firesquiz.closedat once, from inside the call, and is counted as a close in the quiz’s analytics, so the parking close atreadycounts once per page load. Do not readquiz.closedas “the shopper closed it” on this page: theopenedflag already keeps the popup to one open per visit.quiz.viewedfires at mount, before the shopper sees anything.- The overlay’s own X sends the shopper to the store’s front page;
close()from your code hides the overlay in place and keeps the session, soopen()resumes where the shopper was. - The session is created at mount, whether or not the popup ever opens; a page load is a session.
- Keep
visibility: hidden(notdisplay: none) on the container: a mounted fullscreen quiz locks the page’s scrolling untilclose()runs, anddisplay: nonewould not stop that. - Two fullscreen quizzes on one page each get their own overlay; pass the quiz id to
open(quizId)to choose.
