Skip to content

Make the page react to the quiz

Goal: the page around the quiz follows it: a colour per quiz page, the header hidden on the result page, a track that starts once the shopper is in.

Uses: Storefront JS API, page.viewed, quiz.started, quiz.finished, quiz.closed. Nothing to install; no API key. Events fire on the Plus and Enterprise plans.

page.viewed fires when a page lands (the first page at mount, every later one once the server confirmed it). Put its page_key on the root element and let CSS do the rest:

<script>
window.octaneai = window.octaneai || [];
window.octaneai.push(function (octaneai) {
octaneai.on('page.viewed', function (event) {
var page = event.data.object;
var root = document.documentElement;
root.setAttribute('data-quiz-page', page.page_key);
root.setAttribute('data-quiz-page-index', String(page.page_index));
root.classList.toggle('quiz-done', page.terminal_page !== null);
});
octaneai.on('quiz.closed', function () {
document.documentElement.removeAttribute('data-quiz-page');
});
});
</script>
<style>
html[data-quiz-page] body { transition: background-color 400ms; }
html[data-quiz-page="skin"] body { background-color: #f4efe6; }
html[data-quiz-page="goals"] body { background-color: #e6eef4; }
html.quiz-done body { background-color: #111; color: #fff; }
html.quiz-done .site-header { display: none; }
</style>

page_key is the key the page has in the editor. terminal_page is the page key when this landing completed the quiz, otherwise null; quiz.finished fires right after that landing, so either works for “the shopper is on the result”.

Browsers refuse audio.play() without a user gesture, and the first page.viewed fires at mount before the shopper touched anything. quiz.started fires on the shopper’s first answer or first step forward, whichever comes first, which is always after a click, so start there:

window.octaneai = window.octaneai || [];
window.octaneai.push(function (octaneai) {
var track = document.getElementById('quiz-music');
octaneai.on('quiz.started', function () {
if (track) track.play().catch(function () {});
});
octaneai.on('quiz.finished', function () {
if (track) track.pause();
});
});
  • A listener that throws is logged as [OctaneAI] listener for page.viewed threw and never breaks the quiz; there is nothing to catch on your side.
  • play() still rejects when the browser’s autoplay policy blocks it (a shopper who navigated here without interacting with the site); the .catch above keeps that silent.
  • A page-link button’s jump is client-side and is not reported; the next confirmed page names the last confirmed page as previous_page_key.
  • quiz.closed fires only for a fullscreen quiz (its X, or octaneai.close()); an inline quiz has no close.
  • Two quizzes on one page both fire page.viewed; pass { quizId } to on() to follow one of them.
  • Restyling the quiz itself this way does not work: the quiz renders inside a shadow root and its theme variables are set inside it, so host CSS does not reach in, unless the container sets data-shadow-dom="off" (see Rendering without a shadow root).
  • Set localStorage['octaneai:debug'] = '1' in the console to see every event as it fires.