Skip to content

Prefill one quiz from another

Goal: a shopper finishes the skin quiz on the home page; when they open the routine quiz on a collection page, the questions both quizzes share are already answered.

Uses: Storefront JS API, quiz.finished (answers[]), ready(), prefill(), navigate(). Nothing to install; no API key. prefill works on every plan; quiz.finished fires on the Plus and Enterprise plans.

answers[] holds the latest saved answer per question: component_key names the question, value is the answer as stored (an option’s value for a choice, a string for text). Keep only the questions quiz B will reuse, by their keys in quiz A, in sessionStorage, which lives for the tab and is gone when it closes.

<script>
window.octaneai = window.octaneai || [];
window.octaneai.push(function (octaneai) {
var CARRY = ['image_choice-48su5', 'multiple_choice-goals'];
octaneai.on('quiz.finished', function (event) {
var carried = {};
event.data.object.answers.forEach(function (answer) {
if (CARRY.indexOf(answer.component_key) !== -1) carried[answer.component_key] = answer.value;
});
try { sessionStorage.setItem('octane:carried-answers', JSON.stringify(carried)); } catch (e) {}
});
});
</script>

On quiz B’s page, map each carried key to the key of the matching question in quiz B and stage the values with prefill(). prefill stages the values into the page’s answers; they are validated and saved when that page is submitted, by the shopper’s Next or by navigate('next').

<script>
window.octaneai = window.octaneai || [];
window.octaneai.push(function (octaneai) {
var MAP = { 'image_choice-48su5': 'image_choice-skin', 'multiple_choice-goals': 'multiple_choice-goals' };
octaneai.ready(function (api) {
var carried = null;
try { carried = JSON.parse(sessionStorage.getItem('octane:carried-answers')); } catch (e) {}
if (!carried) return;
var values = {};
Object.keys(MAP).forEach(function (fromKey) {
if (carried[fromKey] !== undefined) values[MAP[fromKey]] = carried[fromKey];
});
api.prefill(values);
try { sessionStorage.removeItem('octane:carried-answers'); } catch (e) {}
});
});
</script>

To jump the shopper past a page whose questions are all prefilled, call api.navigate('next') after the prefill in the same callback: the navigate waits for the prefilled values to render, then submits them.

  • A key in values that is not an answer component of quiz B is ignored by prefill; nothing throws. Check the keys in the editor when a value does not show up.
  • A prefilled value the question refuses (an option value quiz B does not have, text past a length limit) is rejected when the page is submitted, as page.rejected with reason: 'invalid'; the shopper sees the same message as for a typed answer.
  • prefill() before the quiz mounted logs [OctaneAI] no quiz on this page yet and does nothing; ready() is what waits for the mount.
  • A choice answer’s value is what the question stores: a list of option values (["Oily"], one entry for a single pick), each the option’s value as set in the editor (its label when no value is set). Pass it back as it came; for the prefill to land, the option must have the same value in both quizzes.
  • Only the current page’s staged values are submitted by a next; a prefilled value for a later page stays staged until that page is submitted, and shows as the selection when the shopper reaches it.
  • getState().answers shows the staged values before they are saved.
  • A text, email or phone answer is the shopper’s own words; the snippet removes the storage entry once it is used, and sessionStorage never leaves the tab. setIdentity({ email, phone }) is the way to prefill identity fields; it never sets marketing consent.
  • Two quizzes on the same page share window.octaneai: pass the quiz id to prefill(values, quizId) when quiz B is not the first one mounted.