Redirect after a quiz finishes
Goal: send the shopper to a page of your choice as soon as they finish a quiz, for example a collection that matches their answers, and send someone who opens their results link later to the same page.
Uses: Storefront JS API. Nothing to install: the API is part of the quiz embed already on the page. Events fire on the Plus and Enterprise plans.
Redirect on the finish event
Section titled “Redirect on the finish event”quiz.finished carries everything the quiz collected: the answers, the points per dimension, the products shown and the discount codes. Each answer names the question (component_key), the value as stored (value), the option ids picked for a choice (option_ids) and the labels the shopper saw (values). Put only choice answers in the URL: a text, email or phone answer is the shopper’s own words and must never land in an address that gets logged.
<script> window.octaneai = window.octaneai || []; window.octaneai.push(function (octaneai) { function redirect(event) { var result = event.data.object; var params = new URLSearchParams();
result.answers.forEach(function (answer) { if (!answer.option_ids.length) return; // choice answers only, never free text params.append(answer.component_key, answer.option_ids.join(',')); }); if (result.terminal_page) params.append('result', result.terminal_page);
window.location.href = '/collections/recommended?' + params.toString(); }
octaneai.on('quiz.finished', redirect); octaneai.on('shared_result.viewed', redirect); // a results link opened later, from an email for example });</script>quiz.finished fires once, after the result page is shown, so the shopper lands on your page rather than staying on the quiz’s own result page.
Results links in emails
Section titled “Results links in emails”Every finished session has a results link (results_url on the people API, the webhooks and the exports), which is what a Klaviyo or other email flow sends as “see your results”. Whoever opens it lands on the quiz page, where the quiz shows its own result page and fires shared_result.viewed instead of quiz.finished: nobody finished a quiz, so no completion is counted. The event carries the same terminal_page, answers, points, formulas and products fields, which is why the one redirect function above serves both and the email visitor reaches your custom page too.
Two differences to keep in mind when a handler is shared: identities and discount_codes are always empty on shared_result.viewed and answers has no email or phone, because the person opening the link may not be the shopper who took the quiz; and session_id is null, with source_session_id naming the session the link belongs to. Keep conversion tracking on quiz.finished only.
Every snippet below runs inside the same window.octaneai.push(function (octaneai) { ... }) callback: before the quiz script loads, window.octaneai is a plain array and octaneai.on does not exist yet.
Pick the page from one answer
Section titled “Pick the page from one answer”Read the answer to a specific question by its component key (the key the question has in the editor; a person’s latest_results[].answers[] on the REST API lists the same keys):
window.octaneai = window.octaneai || [];window.octaneai.push(function (octaneai) { octaneai.on('quiz.finished', function (event) { var skinType = event.data.object.answers.find(function (answer) { return answer.component_key === 'image_choice-48su5'; });
if (skinType && skinType.option_ids.indexOf('dry') !== -1) { window.location.href = '/collections/dry-skin'; } });});Pick the page from the winning dimension
Section titled “Pick the page from the winning dimension”For a points quiz, points maps each dimension id to its total:
window.octaneai = window.octaneai || [];window.octaneai.push(function (octaneai) { octaneai.on('quiz.finished', function (event) { var points = event.data.object.points; var winner = Object.keys(points).sort(function (a, b) { return points[b] - points[a]; })[0];
if (winner) window.location.href = '/collections/' + winner; });});Read the answers before the quiz finishes
Section titled “Read the answers before the quiz finishes”getState() returns what the quiz has so far: answers maps component keys to their values (saved or still on the page), page_key is the current page, and points and discount_codes are the running totals and the codes issued so far.
window.octaneai = window.octaneai || [];window.octaneai.push(function (octaneai) { octaneai.ready(function (api) { api.on('page.viewed', function () { var state = api.getState(); console.log('On page', state.page_key, 'with answers', state.answers); }); });});Every answer shows up in question.answered as it is saved, so you can also react question by question:
window.octaneai = window.octaneai || [];window.octaneai.push(function (octaneai) { octaneai.on('question.answered', function (event) { var answer = event.data.object; console.log(answer.component_key, answer.value, answer.option_ids, answer.values); });});Things to know
Section titled “Things to know”- Set
localStorage['octaneai:debug'] = '1'in the console to see every event logged as it fires. - A listener that throws is logged as
[OctaneAI] listener for quiz.finished threwand never breaks the quiz. - On a plan without the API,
window.octaneaiexists andon()registers, but no event fires and the console says so once.
