Open your own buy flow from a quiz button
Goal: the quiz recommends products, but buying one needs choices a plain add-to-cart cannot carry (a left and a right eye power for contact lenses, an engraving, a size chart of your own). A “Buy now” button on each recommended product opens your quick-buy modal with that product already in it; a “Compare” button on the result page opens your comparison tool with the shopper’s answers and every recommended product; and a signed-in shopper reaches the quiz with the answers you already know filled in.
Uses: Storefront JS API: register, getState, prefill, quiz.finished. Two buttons configured in the editor: a product block action of type “Call registered handler” and a Simple Button with a Custom Action. Nothing to install; no API key. The API, register and prefill included, works on the Plus and Enterprise plans; on another plan the handlers are never called.
In the editor
Section titled “In the editor”- On the result page, open the product block, then Calls to Action, then Add Action, and pick “Call registered handler”. Label it “Buy now” and set the handler name to
quickBuy. Keep “Add to cart” next to it or remove it; that is a merchandising choice. - Add a Simple Button under the product block, set its Click Action to Custom Action, and set the handler name to
compareShades. Label it “Compare on a model”. - Publish.
The params field on either button is optional. Anything you type there reaches your handler as its first argument, parsed as JSON when it is valid JSON.
Register the two handlers
Section titled “Register the two handlers”Register through the queue so the handlers exist before the quiz renders:
<script> window.octaneai = window.octaneai || []; window.octaneai.push(function (octaneai) { octaneai.register('quickBuy', function (params, ctx) { openQuickBuy({ productId: ctx.product_id, variantId: ctx.variant_id, quantity: ctx.quantity, title: ctx.product.title, image: ctx.product.images[0] && ctx.product.images[0].src, sessionId: ctx.session_id }); });
octaneai.register('compareShades', function (params, ctx) { var state = octaneai.getState(ctx.quiz_id); openComparison({ eyeColour: state.answers['eye-colour'], products: state.products.map(function (shown) { return shown.product; }), sessionId: ctx.session_id }); }); });</script>ctx on a product button carries the product the shopper clicked (product_id and variant_id as Shopify GIDs, quantity from the card’s selector, product as the product object) plus session_id, quiz_id, page_key, block_key, component_key and label. A Simple Button carries the same without the product keys; getState() gives it the answers and the recommended products of the page it sits on.
state.answers is keyed by component key, the key the question has in the editor; state.products holds one record per product shown on the landed page, each with its product.
Open your tool the moment the result lands
Section titled “Open your tool the moment the result lands”If the comparison should open on its own, without a click, quiz.finished carries the answers and the products too:
octaneai.on('quiz.finished', function (event) { var finished = event.data.object; var picks = finished.products.map(function (shown) { return shown.product; }); openComparison({ eyeColour: finished.answers['eye-colour'], products: picks });});Register that listener through the queue as well; quiz.finished fires once per session, right after the result page lands.
Prefill the quiz from the account
Section titled “Prefill the quiz from the account”When you already know an answer, stage it before the shopper reaches that page. The values go through the same validation as a typed answer when the page is submitted:
octaneai.ready(function (octaneai) { if (customer && customer.eyeColour) { octaneai.prefill({ 'eye-colour': customer.eyeColour, 'wear-frequency': customer.frequency }); }});prefill(...) followed by navigate('next') in the same call submits the prefilled page at once, for a shopper who should skip it entirely.
Errors to handle
Section titled “Errors to handle”- A button whose handler is not registered logs
simple_button: handler 'quickBuy' not found in window.PhoenixHandlers(or the product block’s equivalent) and shows the shopper nothing. Register through the queue, not onDOMContentLoaded, so the order never depends on script timing. - A handler that throws is logged as a click handler error and the quiz continues; keep your own try/catch around the modal code if it can fail on a missing element.
ctx.session_idisnullwhen the session could not be opened (an offline test page, a blocked request); the product keys are still there, so the quick buy still works.prefillignores keys that are not answer components; check the component keys in the editor when nothing lands.- On a plan without the API the buttons still call the handlers, but
quiz.finishedandproduct.clickeddo not fire; see Plans.
