How to Build a Custom Quiz on Shopify Using Liquid + Vanilla JavaScript (Step-by-Step Guide)

by Jay B, Shopify Expert

No apps, no frameworks - just Liquid, HTML, CSS variables, and a single JavaScript file.

Quizzes are an incredibly powerful way to improve product discovery, personalise customer journeys, and boost conversion rates.

But most Shopify quiz apps are slow, bloated, expensive, or hard to customise.

So today, you’ll learn how to build your own fully custom Shopify quiz using:

  • A single Shopify section (quiz.liquid)

  • A single JavaScript file (quiz.js)

  • Native Web Component

  • CSS variables for light mode / dark mode theming

  • Zero external libraries

And it works in any Shopify theme.


📌 What We’re Building

You're building a “Path Finder” style quiz where customers answer questions, and you show a personalised collection recommendation at the end.

Features:

  • Step-based quiz UI

  • Option selection with nice interaction

  • Progress bar

  • Custom results screen

  • Fully customisable quiz logic

  • Accessible: aria-live, keyboard-friendly

  • Optional GA4 tracking (bonus section)

Note

This tutorial was created using the latest version (3.1.0) of Shopify’s Horizon theme.

The logic may differ slightly if your theme uses an older architecture.


Step 1: Create the Quiz Section

First, we need a Liquid section to hold the quiz. This is where Shopify will render the HTML structure and include our JavaScript.

File path:
/sections/quiz.liquid

In your Shopify theme editor, navigate to the Sections folder and create a new blank file named quiz.liquid.


Step 1.1: Create the Quiz Section

Paste the following code inside:

<div class="section-background"></div>

<div id="quizWrapper" class="section section--{{ section.settings.section_width }} {% if section.settings.quiz_theme == 'light' %}theme-light{% endif %}">
  <intention-quiz class="quiz-card">

    <header class="quiz-header">
      <h2>My Path Finder</h2>
      <p id="stepTitle">Loading...</p>
      <div class="progress-bar-container">
        <div id="progressBar" class="progress-bar" style="width: 0%;"></div>
      </div>
    </header>

    <div id="quizContent" class="quiz-step-content" aria-live="polite" aria-atomic="true" role="status">
      <p id="loading-message">Loading quiz step...</p>
    </div>

    <footer class="quiz-footer">
      <button id="prevBtn" class="size-style button nav-button" disabled>
        <i>{{- 'icon-left.svg' | inline_asset_content -}}</i> Back
      </button>
    </footer>

  </intention-quiz>
</div>

<script src="{{ 'quiz.js' | asset_url }}" type="module" fetchpriority="low"></script>

Key Points:

  • We wrap the quiz in a <intention-quiz> custom element.

  • #quizContent will dynamically render each quiz step.

  • #prevBtn allows navigation back to the previous step.

  • quiz.js will handle all logic for option selection and results.


Step 1.2: Add CSS Styles

Inside the quiz.liquid section, we include all necessary styles:

<style>
/* Dark Theme Variables */
:root {
  --color-primary: #111418;
  --color-secondary: #22262a;
  --color-accent: #2c7be0;
  --color-text: #e0e0e0;
  --color-light-text: #a0a0a0;
  --color-faded-text: #6b7280;
  --color-warning: #facc15;
  --color-main-option-text: #ffffff;
  --color-background: #333333;
  --color-hover: #444444;
  --color-hover-border: #555555;
}

/* Light Theme Override */
.theme-light {
  --color-primary: #f9fafb;
  --color-secondary: #ffffff;
  --color-accent: #2c7be0;
  --color-text: #111418;
  --color-light-text: #4b5563;
  --color-faded-text: #6b7280;
  --color-warning: #f59e0b;
  --color-main-option-text: #111418;
  --color-background: #d0d0d0;
  --color-hover:rgb(183, 181, 181);
  --color-hover-border:rgb(149, 149, 149);
}

/* Quiz Card Styles */
#quizWrapper {
  background-color: var(--color-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 50px 0;
  box-sizing: border-box;
}

.quiz-card {
  background-color: var(--color-secondary);
  max-width: 600px;
  width: 100%;
  border-radius: 16px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
  border: 1px solid var(--color-background);
  padding: 30px;
  transition: all 0.3s ease-in-out;
}

.quiz-card h2,
#stepTitle {
  color: var(--color-light-text);
}

.progress-bar-container {
  height: 8px;
  background-color: var(--color-background);
  border-radius: 4px;
  margin-bottom: 25px;
  overflow: hidden;
}

.progress-bar {
  height: 100%;
  background-color: var(--color-accent);
  border-radius: 4px;
  transition: width 0.3s ease-in-out;
}

.quiz-step-content {
  min-height: 300px;
  transition: opacity 0.5s ease-in-out;
}

.quiz-question {
  font-size: 1.25rem;
  font-weight: 600;
  margin-bottom: 1.5rem;
  color: var(--color-text);
}

.option-button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 15px 20px;
  margin-bottom: 12px;
  background-color: var(--color-background);
  color: var(--color-main-option-text);
  border-radius: 8px;
  cursor: pointer;
  transition: background-color 0.2s, box-shadow 0.2s, border-color 0.2s;
  border: 2px solid var(--color-background);
  text-align: left;
}

.option-button:focus {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

.option-text-group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  flex-grow: 1;
}

.option-text-group span:first-child {
  font-weight: 600;
}

.option-description {
  font-size: 0.875rem;
  color: var(--color-light-text);
  margin-top: 4px;
  font-weight: 400;
}

.option-button:hover:not(.selected) {
  background-color: var(--color-hover);
  border-color: var(--color-hover-border);
}

.option-button.selected {
  background-color: var(--color-accent);
  border-color: var(--color-accent);
}

.quiz-footer {
  margin-top: 2rem;
  display: flex;
  justify-content: space-between;
}

.nav-button {
  display: inline-flex;
  align-items: center;
}

.nav-button i {
  width: 1.25rem;
  height: 1.25rem;
}

.result-center {
  text-align: center;
}

.result-description {
  font-size: 1.125rem;
  margin-bottom: 1.5rem;
  color: var(--color-light-text);
}

.result-box {
  background-color: var(--color-background);
  padding: 20px;
  border-radius: 8px;
  border-left: 5px solid var(--color-accent);
  margin-top: 20px;
}

.result-box p:first-child {
  font-size: 1rem;
  color: var(--color-light-text);
}

.result-collection-name {
  font-size: 2.25rem;
  font-weight: 800;
  margin-top: 0.5rem;
  padding-bottom: 0.5rem;
}

.result-meta {
  margin-top: 1rem;
  color: var(--color-light-text);
}

.result-link-button {
  display: inline-block;
  margin-top: 30px;
  font-size: 1.1rem;
  background-color: var(--color-accent);
  color: var(--color-primary);
  text-decoration: none;
  padding: 12px 24px;
  border-radius: 8px;
  transition: background-color 0.2s;
}

.result-link-button:hover {
  background-color: #1c5bbf;
}
</style>

Top tip

By using variables, you can easily switch themes by toggling the class theme-light on the section wrapper. This allows non-developers to control the look directly from the Shopify editor.


Step 1.3: Add Schema Definition

Inside the quiz.liquid section finally add the schema definition:**

{% schema %}
{
  "name": "Quiz",
  "tag": "section",
  "class": "quiz-wrapper section-wrapper",
  "settings": [
    {
      "type": "select",
      "id": "quiz_theme",
      "label": "Quiz Theme",
      "default": "dark",
      "options": [
        { "value": "dark", "label": "Dark" },
        { "value": "light", "label": "Light" }
      ]
    }
  ],
  "presets": [
    {
      "name": "Quiz",
      "category": "Custom"
    }
  ]
}
{% endschema %}

Step 2: Add the Javascript (quiz.js)

File path:
/assets/quiz.js

In your Shopify theme editor, navigate to the Assets folder and create a new blank file named quiz.js.

The JavaScript handles dynamic quiz behaviour: rendering steps, option selection, progress tracking, and final recommendations.

import { Component } from '@theme/component';

class IntentionQuiz extends Component {
    constructor() {
        super();
        this.initialLoadComplete = false;

        this.steps = [
            {
                id: 1,
                title: "Initial Focus",
                question: "What primary intention or goal are you currently focused on achieving?",
                options: [
                    { text: "Connection & Purpose", value: "Connection & Purpose", description: "Deepening bonds with others and finding meaning in your life's path." },
                    { text: "Courage & Action", value: "Courage & Action", description: "Seeking inner bravery to overcome fears and move forward decisively." },
                    { text: "Focus & Clarity", value: "Focus & Clarity", description: "Eliminating mental fog to achieve clear decision-making and concentration." },
                    { text: "Protection & Defence", value: "Protection & Defence", description: "Creating energetic boundaries and warding off negativity or challenging influences." },
                    { text: "Strength & Endurance", value: "Strength & Endurance", description: "Building physical, mental, and emotional resilience for long-term effort." },
                    { text: "Wealth & Prosperity", value: "Wealth & Prosperity", description: "Attracting abundance in all forms, including financial and material well-being." },
                    { text: "Wellness & Health", value: "Wellness & Health", description: "Nurturing the physical body, promoting vitality, and restoring balance." }
                ],
                type: 'intention'
            },
            {
                id: 2,
                title: "Emotional Anchor",
                question: "What frequency or desired state do you want to anchor in your daily life?",
                options: [
                    { text: "Serene and Balanced", value: "Serene", description: "A state of deep calm, emotional resilience, and quiet, effortless grace." },
                    { text: "Powerful and Unstoppable", value: "Unstoppable", description: "Feeling motivated, driven, and capable of overcoming any obstacle." },
                    { text: "Sharp and Decisive", value: "Decisive", description: "Having mental clarity, precision, and the ability to make choices quickly." },
                    { text: "Grounded and Present", value: "Grounded", description: "Feeling secure, stable, and deeply connected to the present moment." }
                ],
                type: 'frequency'
            },
            {
                id: 3,
                title: "Product Expression",
                question: "Which expression best suits your style and daily lifestyle?",
                options: [
                    { text: "Bracelet (Tactile reminder, easily visible)", value: "Bracelet", description: "Kept close on the wrist, perfect for grounding and constant visual reference." },
                    { text: "Necklace (Close to the heart, subtle statement)", value: "Necklace", description: "Worn over the heart or throat chakra, ideal for emotional and expressive intentions." }
                ],
                type: 'product_type'
            }
        ];

        // The resultsMatrix maps user answers (intention + frequency) to personalized recommendations
        // This is the key for quiz personalisation
        this.resultsMatrix = {
            "Connection & Purpose": {
                "Serene": { description: "Your path to Connection & Purpose is anchored in Serenity..." },
                "Unstoppable": { description: "Your intention of Connection & Purpose is best fueled by being Unstoppable..." },
                "Decisive": { description: "To achieve Connection & Purpose, you need Decisiveness..." },
                "Grounded": { description: "The foundation for Connection & Purpose is the Grounded state..." }
            },
            "Courage & Action": {
                "Serene": { description: "To master Courage & Action, anchor Serenity..." },
                "Unstoppable": { description: "Your intention of Courage & Action requires the full power of being Unstoppable..." },
                "Decisive": { description: "A Decisive state is the sharp focus needed to conquer hesitation..." },
                "Grounded": { description: "The core stability required for Courage & Action comes from being Grounded..." }
            },
            "Focus & Clarity": {
                "Serene": { description: "The deepest source of Focus & Clarity is Serenity..." },
                "Unstoppable": { description: "Your desire for Focus & Clarity is magnified by being Unstoppable..." },
                "Decisive": { description: "To truly master Focus & Clarity, anchor Decisiveness..." },
                "Grounded": { description: "Achieve Focus & Clarity by using the Grounded state..." }
            },
            "Protection & Defence": {
                "Serene": { description: "The highest form of Protection & Defence comes from Serenity..." },
                "Unstoppable": { description: "For powerful Protection & Defence, anchor being Unstoppable..." },
                "Decisive": { description: "To create strong Protection & Defence, you must anchor Decisiveness..." },
                "Grounded": { description: "The most stable Protection & Defence is rooted in being Grounded..." }
            },
            "Strength & Endurance": {
                "Serene": { description: "Your goal of Strength & Endurance is fueled by Serenity..." },
                "Unstoppable": { description: "To achieve peak Strength & Endurance, anchor being Unstoppable..." },
                "Decisive": { description: "Your goal of Strength & Endurance is best fueled by Decisiveness..." },
                "Grounded": { description: "The core of Strength & Endurance is being Grounded..." }
            },
            "Wealth & Prosperity": {
                "Serene": { description: "Your manifestation of Wealth & Prosperity is amplified by Serenity..." },
                "Unstoppable": { description: "To achieve Wealth & Prosperity, anchor being Unstoppable..." },
                "Decisive": { description: "A Decisive state is key to managing Wealth & Prosperity..." },
                "Grounded": { description: "The Grounded state is the anchor for establishing a solid foundation..." }
            },
            "Wellness & Health": {
                "Serene": { description: "The path to Wellness & Health is paved with Serenity..." },
                "Unstoppable": { description: "To boost Wellness & Health, anchor being Unstoppable..." },
                "Decisive": { description: "A Decisive state is essential for long-term Wellness & Health..." },
                "Grounded": { description: "Achieve true Wellness & Health through being Grounded..." }
            }
        };
    }

    #controller = new AbortController();

    connectedCallback() {
        super.connectedCallback();
        const { signal } = this.#controller;

        this.#setDefaultState();
        this.quizContent = this.querySelector('#quizContent');
        this.prevBtn = this.querySelector('#prevBtn');
        this.progressBar = this.querySelector('#progressBar');
        this.stepTitle = this.querySelector('#stepTitle');

        this.#renderStep(this.currentStep);

        this.prevBtn.addEventListener('click', (event) => this.#prevStep(event), { signal });
    }

    disconnectedCallback() {
        super.disconnectedCallback();
        this.#controller.abort();
    }

    #setDefaultState() {
        this.currentStep = 1;
        this.totalSteps = this.steps.length;
        this.selectionStepsCount = 3;
        this.selections = {};
    }

    // Renders each quiz step dynamically
    #renderStep(stepIndex) {
        const step = this.steps[stepIndex - 1];
        if (!step || !this.quizContent) return;

        if (this.stepTitle) {
            this.stepTitle.textContent = step.title;
        }
        this.#updateProgressBar(stepIndex);

        this.quizContent.style.opacity = '0';

        setTimeout(() => {
            let html = `<h3 class="quiz-question">${step.question}</h3><div class="options-group" data-type="${step.type}">`;

            const selectedValue = this.selections[step.type];
            step.options.forEach(option => {
                const isSelected = selectedValue === option.value;
                const selectedClass = isSelected ? 'selected' : '';
                const ariaPressed = isSelected ? 'true' : 'false';
                const descriptionHtml = option.description ? `<span class="option-description">${option.description}</span>` : '';

                html += `
                    <button class="option-button ${selectedClass}" data-type="${step.type}" data-value="${option.value}" role="button" aria-pressed="${ariaPressed}" aria-describedby="option-title">
                        <div class="option-text-group">
                            <span class="option-title">${option.text}</span>
                            ${descriptionHtml}
                        </div>
                    </button>
                `;
            });

            html += `</div>`;
            this.quizContent.innerHTML = html;

            this.#attachStepListeners(step.type);

            this.quizContent.style.opacity = '1';

            if (this.initialLoadComplete) { 
                this.#scrollToTop();
            } else {
                this.initialLoadComplete = true;
            }
        }, 250);
    }

    // Generates and renders final recommendation
    #renderResults() {
        const recommendedCollection = this.selections['intention'] || 'Connection & Purpose';
        const emotionalFrequency = this.selections['frequency'] || 'Serene';
        const rawProductType = this.selections['product_type'] || 'Bracelet';

        let productFilterValue = '';
        if (rawProductType.includes('Bracelet')) {
            productFilterValue = 'Bracelets';
        } else if (rawProductType.includes('Necklace')) {
            productFilterValue = 'Necklaces';
        }
        const productFilter = `?filter.p.product_type=${productFilterValue}`;

        const generateSlug = (text) => text.toLowerCase().replace(/ & /g, '-').replace(/ /g, '-').replace(/[^\w-]+/g, '');
        const collectionSlug = generateSlug(recommendedCollection);
        const collectionUrl = `/collections/${collectionSlug}${productFilter}`;

        const resultData = this.resultsMatrix[recommendedCollection]?.[emotionalFrequency];
        const description = resultData ? resultData.description : '';

        if (this.quizContent) {
            this.quizContent.style.opacity = '0';
        }
        
        setTimeout(() => {
          const resultHtml = `
              <div class="result-center">
                  <h3 class="result-title">Your Personalised Recommendation</h3>
                  <p class="result-description">${description}</p>
                  <div class="result-box">
                      <p>Your Intention Focus:</p>
                      <p class="result-collection-name">${recommendedCollection}</p>
                  </div>
                  <a class="result-link-button" href="${collectionUrl}">View Collection</a>
              </div>
          `;

          if (this.quizContent) {
              this.quizContent.innerHTML = resultHtml;
          }

          this.prevBtn?.classList.add('hidden');
            
            if (this.stepTitle) {
                this.stepTitle.textContent = 'Recommendation Complete';
            }
            if (this.progressBar) {
                this.progressBar.style.width = '100%';
            }
            
            if (this.quizContent) {
                this.quizContent.style.opacity = '1';

                this.#scrollToTop(); 
            }
        }, 250);
    }

    #updateProgressBar(stepIndex) {
        const step = this.steps[stepIndex - 1];
        if (!step) return;

        if (this.stepTitle) {
            this.stepTitle.textContent = `Step ${Math.min(stepIndex, this.selectionStepsCount)} of ${this.selectionStepsCount}: ${step.title}`;
        }
        
        if (this.progressBar) {
            const currentSelectionStep = Math.min(stepIndex, this.selectionStepsCount);
            const progress = (currentSelectionStep / this.selectionStepsCount) * 100;
            this.progressBar.style.width = `${progress}%`;
        }
        
        if (this.prevBtn) {
            this.prevBtn.disabled = stepIndex === 1;
        }
    }

    #attachStepListeners(type) {
        const { signal } = this.#controller;
        const newOptionBtns = this.quizContent.querySelectorAll(`.option-button[data-type="${type}"]`);
        newOptionBtns.forEach(btn => {
            btn.addEventListener('click', (event) => this.#selectOption(event), { signal });
        });
    }

    // Handles option selection and stores user's choice
    #selectOption(event) {
        event.preventDefault();
        const button = event.currentTarget;
        const type = button?.dataset?.type;
        const value = button?.dataset?.value;
        if (!button || !type || !value) return;

        this.selections[type] = value;

        const siblingBtns = this.quizContent.querySelectorAll(`.option-button[data-type="${type}"]`) || [];
        siblingBtns.forEach(btn => btn.classList.toggle('selected', btn === button));

        this.#nextStep();
    }

    // Advances to next step or shows results
    #nextStep() {
        if (this.currentStep < this.totalSteps) {
            this.currentStep++;
            this.#renderStep(this.currentStep);
        } else {
            this.#renderResults();
        }
    }

    // Returns to previous step
    #prevStep(event) {
        event.preventDefault();
        if (this.currentStep > 1) {
            this.currentStep--;
            this.#renderStep(this.currentStep);
        }
    }

    #scrollToTop() {
        if (!this.isConnected) return; 

        const bodyStyles = window.getComputedStyle(document.body);
        
        let headerHeight = bodyStyles.getPropertyValue('--header-height').trim();

        headerHeight = parseFloat(headerHeight) || 0;
        
        const rect = this.getBoundingClientRect();
        
        const elementTopInDocument = rect.top + window.scrollY;
        
        const targetScrollPosition = elementTopInDocument - headerHeight;

        if (rect.top < headerHeight || rect.top > window.innerHeight) {
            window.scrollTo({
                top: targetScrollPosition,
                behavior: 'smooth'
            });
        }
    }
}

if (!customElements.get('intention-quiz')) {
    customElements.define('intention-quiz', IntentionQuiz);
}

Key Points:

This script will:

  • Render quiz steps dynamically

  • Handle option selection

  • Update the progress bar

  • Display a final recommendation


Step 4: Add the Section to Your Shopify Page

  1. Go to Online Store → Themes → Customise

  2. Add the Quiz section to your page.

  3. Save and preview. You should now have a fully interactive quiz!


Step 5: Next Steps & Customisation

  • Add more steps or options by editing this.steps.

  • Customise styling in quiz.liquid’s <style> block.

  • Enhance results with images or product links.

  • Later, you can integrate GA4 tracking.


Bonus: Tracking

GA4 Event Tracking

To track quiz interactions in GA4, add this helper method:

#trackGA4Event(eventName, params) {
  if (typeof gtag === 'function') gtag('event', eventName, params);
}

Call it after selections and at the end of the quiz:

// Call after each selection
this.#trackGA4Event('quiz_step_complete', { step_number: this.currentStep, selection_value: value });

// Call at quiz completion
this.#trackGA4Event('quiz_complete', { final_intention: recommendedCollection });

With GA4, you can track user engagement for retargeting.


Troubleshooting

If you encounter issues while setting up or running your custom quiz, check the following common areas:

Quiz Not Loading or Stuck on "Loading..."

  • File Paths: Ensure your files are saved in the correct locations:

    • Liquid: /sections/quiz.liquid

    • JavaScript: /assets/quiz.js

  • Asset Link: In quiz.liquid, verify the script tag correctly links the asset:

<script src="{{ 'quiz.js' | asset_url }}" type="module" fetchpriority="low"></script>
  • Custom Element: Confirm the IntentionQuiz class is registered at the bottom of quiz.js:
if (!customElements.get('intention-quiz')) {
    customElements.define('intention-quiz', IntentionQuiz);
}

Options Not Working / Not Advancing

  • Console Errors: Open your browser's Developer Console and check for JavaScript errors. Common issues include typos in variable names or failed property access.

  • Data Attributes: Ensure the option buttons in the dynamically rendered HTML have the correct data-type and data-value attributes, which are used by the #selectOption method.

<button class="option-button" data-type="intention" data-value="..."></button>
  • Listener Attachment: Check the #attachStepListeners function in quiz.js to confirm that event listeners are being successfully added to the newly rendered buttons after the step transitions.

Some browsers block third-party cookies — test in a private window or increase the expiration time in the script.


Results Are Incorrect

  • this.resultsMatrix Keys: Verify that the keys in your this.resultsMatrix object exactly match the value strings used in your options data (e.g., "Connection & Purpose" and "Serene" must match perfectly).

  • Slug Generation: If your results link is broken, inspect the generateSlug function in #renderResults to ensure it converts your selection text into a valid, lower-case URL path (e.g., Wealth & Prosperity becomes /collections/wealth-prosperity).


How This Tutorial Came to Be

The idea for this tutorial was born out of a common necessity for high-conversion e-commerce stores: personalised product discovery. Third-party quiz apps often charge high monthly fees and introduce significant performance overhead (slow load times).

This discovery led to the development of this guide, which provides a new, much better solution: a custom, lightweight quiz built entirely with Shopify Liquid and Vanilla JavaScript. This approach gives the merchant full control over the design, speed, and data, eliminating monthly fees and unnecessary external dependencies.

This implementation is simple, reliable, and perfectly suited for personalising recommendations based on customer preferences. There is plenty of room for further enhancements—for example, it could easily be extended to integrate complex product filtering logic or automatically add the recommended item to the cart upon completion.


Summary

You’ve now implemented a lightweight, native, and customizable Path Finder Quiz for Shopify that:

  • Engages Customers with a clear, step-by-step flow.

  • Tracks Selections using Vanilla JavaScript objects.

  • Delivers Personalised Recommendations based on a custom resultsMatrix.

  • Integrates Natively using Liquid sections and theme assets, requiring no third-party apps.

This quiz is perfect for guiding customers to the right collection, boosting engagement, and easily extending for GA4 tracking for powerful marketing campaigns.


Advanced Customisation & Consulting

You've built a fast, effective quiz! For merchants looking to turn this quiz into a powerful revenue and lead generation engine, the next step is advanced customisation. These complex features require updates to both your Liquid schema and JavaScript logic.

If you're ready to unlock the full potential of your quiz, these are the high-impact projects I can help you implement:

1. ⬆️ Upsell Integration & Revenue Boost

Maximize your Average Order Value (AOV) by dynamically presenting high-value, complementary products immediately on the results screen.

  • The Upgrade: Modifying the Liquid schema to allow non-developers to select 2-3 specific upsell products from the Theme Editor.

  • The Logic: Advanced JavaScript logic that checks the customer's final recommended collection and injects pre-selected, visually appealing upsell product cards next to the final link.

  • The Goal: Guaranteeing the upsell is hyper-relevant to the customer's stated needs and ensuring maximum conversion.

2. 🌳 Multi-Path (Branching) Logic

Move beyond the current linear flow to create a truly personalised quiz experience where the questions adapt based on previous answers.

  • The Upgrade: Restructuring the this.steps object in quiz.js to define conditional paths (e.g., if a customer chooses 'Wellness,' skip the 'Wealth' questions).

  • The Logic: Rewriting the #nextStep function to dynamically read the selected option's unique ID to determine the next question, instead of just incrementing the step number.

  • The Goal: Increase user engagement and collect better data by eliminating irrelevant questions, leading to even more precise final recommendations.

3. 📧 Klaviyo/Email Marketing Integration

Convert high-intent quiz takers into long-term subscribers by securely passing their personalised results directly to your email platform.

  • The Upgrade: Integrating an email capture form immediately before the results are displayed.

  • The Logic: Intergrate with Klaviyo to send the customer's email address and their quiz results (like final_intention: 'Wealth & Prosperity').

  • The Goal: Enable highly segmented, automated email flows (e.g., "Welcome email series for customers interested in 'Courage & Action'"), drastically improving ROI on email marketing.

👉 Ready to take your quiz to the next level? Let me know which advanced feature you'd like to implement, and we can discuss a custom setup plan.

More articles

How to Automatically Apply Multiple Discount Codes in Shopify (Step-by-Step Guide)

Save time and delight shoppers! Learn how to automatically apply multiple Shopify discount codes with a simple, lightweight setup — perfect for marketing campaigns and special offers.

Read more

Level Up Your Shopify Store

Is your store underperforming? I specialize in creating robust Shopify solutions that boost conversions and improve user experience. Let's talk about your goals and build a store that truly performs for your business.