> ## Documentation Index
> Fetch the complete documentation index at: https://docs.landerlab.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Use Quiz Events API for Tracking and Automation

> Use Quiz Events API to track user actions, monitor quiz lifecycle events, and trigger custom logic for advanced funnel optimization.

The LanderLab Quiz Events API publishes the lifecycle of your quiz so you can interact with it using custom JavaScript. This is particularly useful if you want to implement your own granular tracking or if you want to interact with your quiz data client-side.

## Introduction

The Events API allows you to listen to different lifecycle events of your quiz and execute custom code when these events occur. Here’s a basic example:

```javascript theme={null}
window.addEventListener('ll-quiz-init', (event) => {
    console.log('ll-quiz init:', event.detail.quizId);
    const llQuizApi = event.detail.llQuizApi;
    
    // Use llQuizApi here
});
```

where **ll-quiz-init** is the Event Name of the lifecycle event.

## Events Overview

Your quiz emits the following events per lifecycle event:

| Event Name           | Lifecycle Event                                                                                              | Data Passed                                                                                      |
| :------------------- | :----------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------- |
| ll-quiz-init         | When the quiz loads initially and is bound to the DOM                                                        | quizId, llQuizApi                                                                                |
| ll-quiz-submit       | When the quiz gets submitted                                                                                 | quizId, stepId, stepName, fields, fieldsSimple, llQuizApi, response                              |
| ll-quiz-step-view    | When a step is visited                                                                                       | quizId, stepId, stepName, fields, fieldsSimple, llQuizApi                                        |
| ll-quiz-step-leave   | When navigating away from a step                                                                             | quizId, stepName, llQuizApi                                                                      |
| ll-quiz-exit         | When the tab/window in which the quiz lives gets closed                                                      | quizId, llQuizApi                                                                                |
| ll-quiz-button-click | When a button block is clicked (DefaultButton, Continue, Previous)                                           | quizId, blockId, blockName, stepId, stepName, llQuizApi                                          |
| ll-quiz-input-click  | When a Multiple Choice or Image Choice option is clicked                                                     | quizId, blockId, blockName, stepId, stepName, optionId, optionValue, optionLabel, llQuizApi      |
| ll-quiz-value-change | When the value of a block changes (typed fields when the visitor leaves the field, other inputs immediately) | quizId, blockId, blockName, blockType, stepId, stepName, value, previousValue, source, llQuizApi |

## ll-quiz-init Event

**When:** When the quiz loads initially and is bound to the DOM.

**Event Detail:**

* **quizId** (string): The unique identifier of the quiz
* **llQuizApi** (LlQuizApi): The LlQuiz API instance for interacting with the quiz

**Example:**

```javascript theme={null}
window.addEventListener('ll-quiz-init', (event) => {
    const { quizId, llQuizApi } = event.detail;
    console.log('Quiz initialized:', quizId);
    
    // Access the LlQuiz API
    const currentStepId = llQuizApi.getCurrentStepID();
    const allBlocks = llQuizApi.getBlocks();
});
```

## ll-quiz-submit Event

**When:** When the quiz gets submitted (typically when the submit button is clicked and the form is successfully submitted).

**Event Detail:**

* **quizId** (string): The unique identifier of the quiz
* **stepId** (string): The step ID where submission occurred
* **stepName** (string): The step name where submission occurred
* **fields** (Field\[]): Array of field objects with detailed information (see Fields Structure below)
* **fieldsSimple** (FieldsSimple): Key-value object with label as key and value as string (see FieldsSimple Structure below)
* **llQuizApi** (LlQuizApi): The LlQuiz API instance for interacting with the quiz
* **response** (any): The API response from the submission endpoint. Can be:
  * The parsed JSON response if the API returns JSON
  * The Response object if it’s not JSON
  * null if the API call failed

**Example:**

```javascript theme={null}
window.addEventListener('ll-quiz-submit', (event) => {
    const { quizId, stepId, stepName, fields, fieldsSimple, llQuizApi, response } = event.detail;
    console.log('Quiz submitted:', quizId);
    console.log('Submitted from step:', stepName);
    console.log('Submitted data:', fieldsSimple);
    console.log('API Response:', response);
    
    // Send to your analytics platform
    if (window.gtag) {
        window.gtag('event', 'quiz_submit', {
            'quiz_id': quizId,
            'step_id': stepId,
            'step_name': stepName
        });
    }
});
```

## ll-quiz-step-view Event

**When:** When a step is visited (whenever the user navigates to a new step).

**Event Detail:**

* **quizId** (string): The unique identifier of the quiz
* **stepId** (string): The step ID that was viewed
* **stepName** (string): The step name that was viewed
* **fields** (Field\[]): Array of field objects from the current step (see Fields Structure below)
* **fieldsSimple** (FieldsSimple): Key-value object with label as key and value as string for the current step (see FieldsSimple Structure below)
* **llQuizApi** (LlQuizApi): The LlQuiz API instance for interacting with the quiz

**Example:**

```javascript theme={null}
window.addEventListener('ll-quiz-step-view', (event) => {
    const { quizId, stepId, stepName, fields, fieldsSimple, llQuizApi } = event.detail;
    console.log('Quiz:', quizId);
    console.log('Step viewed:', stepName);
    console.log('Current step data:', fieldsSimple);
    
    // Track step view
    if (window.dataLayer) {
        window.dataLayer.push({
            'event': 'll_quiz_step_view',
            'quiz_id': quizId,
            'step_id': stepId,
            'step_name': stepName
        });
    }
});
```

## ll-quiz-step-leave Event

**When:** When navigating away from a step (before the next step is shown).

**Event Detail:**

* **quizId** (string): The unique identifier of the quiz
* **stepName** (string): The step name being left
* **llQuizApi** (LlQuizApi): The LlQuiz API instance for interacting with the quiz

**Example:**

```javascript theme={null}
window.addEventListener('ll-quiz-step-leave', (event) => {
    const { quizId, stepName, llQuizApi } = event.detail;
    console.log('Quiz:', quizId);
    console.log('Leaving step:', stepName);
    
    // Get current step information before leaving
    const currentStepId = llQuizApi.getCurrentStepID();
    console.log('Current step ID:', currentStepId);
});
```

## ll-quiz-exit Event

**When:** When the tab/window in which the quiz lives gets closed.

This event is based on the native pagehide event, which, unfortunately, is not entirely reliable. The event may not fire in all scenarios (e.g., force quit, browser crash, or certain mobile browser behaviors). Don’t rely on it for critical operations.

**Event Detail:**

* **quizId** (string): The unique identifier of the quiz
* **llQuizApi** (LlQuizApi): The LlQuiz API instance for interacting with the quiz

**Example:**

```javascript theme={null}
window.addEventListener('ll-quiz-exit', (event) => {
    const { quizId, llQuizApi } = event.detail;
    console.log('Quiz exited:', quizId);
    
    // Track exit event (e.g., for analytics)
    if (window.gtag) {
        window.gtag('event', 'quiz_exit', {
            'quiz_id': quizId
        });
    }
    
    // Note: This event may not fire reliably in all scenarios
    // Don't rely on it for critical operations
});
```

## ll-quiz-button-click Event

**When:** When a button block is clicked. This includes DefaultButton, Continue, Previous, and Submit button blocks.

**Event Detail:**

* **quizId** (string): The unique identifier of the quiz
* **blockId** (string): The unique identifier of the button block that was clicked
* **blockName** (string): The name property of the button block
* **stepId** (string): The step ID where the button is located
* **stepName** (string): The step name where the button is located
* **llQuizApi** (LlQuizApi): The LlQuiz API instance for interacting with the quiz

**Example:**

```javascript theme={null}
window.addEventListener('ll-quiz-button-click', (event) => {
    const { quizId, blockId, blockName, stepId, stepName, llQuizApi } = event.detail;
    console.log('Button clicked:', blockName);
    console.log('In step:', stepName);
    
    // Track button clicks for analytics
    if (window.gtag) {
        window.gtag('event', 'button_click', {
            'quiz_id': quizId,
            'block_id': blockId,
            'block_name': blockName,
            'step_id': stepId,
            'step_name': stepName
        });
    }
    
    // Perform custom logic based on button type
    if (blockName === 'submit-button') {
        console.log('Submit button was clicked!');
    }
});
```

## ll-quiz-input-click Event

**When:** When a Multiple Choice option or Image Choice option is clicked.

**Event Detail:**

* **quizId** (string): The unique identifier of the quiz
* **blockId** (string): The unique identifier of the block where the option was clicked
* **blockName** (string): The name property of the block
* **stepId** (string): The step ID where the block is located
* **stepName** (string): The step name where the block is located
* **optionId** (string): The unique identifier of the clicked option
* **optionValue** (string): The value of the clicked option
* **optionLabel** (string): The label of the clicked option
* **llQuizApi** (LlQuizApi): The LlQuiz API instance for interacting with the quiz

**Example:**

```javascript theme={null}
window.addEventListener('ll-quiz-input-click', (event) => {
    const { quizId, blockId, blockName, stepId, stepName, optionId, optionValue, optionLabel, llQuizApi } = event.detail;
    console.log('Option clicked:', optionLabel);
    console.log('In block:', blockName);
    console.log('In step:', stepName);
    
    // Track option clicks for analytics
    if (window.gtag) {
        window.gtag('event', 'option_click', {
            'quiz_id': quizId,
            'block_id': blockId,
            'block_name': blockName,
            'step_id': stepId,
            'step_name': stepName,
            'option_id': optionId,
            'option_value': optionValue,
            'option_label': optionLabel
        });
    }
    
    // Perform custom logic based on option selection
    if (optionValue === 'premium-plan') {
        console.log('Premium plan selected!');
    }
});
```

## ll-quiz-value-change Event

**When:** When the value of a block changes. Each event reports one answer, with the value before and after the change:

* **Typed fields** (Text, Textarea, Number, Email, Phone Number, Zip Code, Birth Date, Google Address) emit the event when the visitor leaves the field (blur, Tab, Enter) or leaves the step. Keystrokes do not emit events.
* **All other inputs** (Multiple Choice, Image Choice, Select, Checkbox, Range Slider, Date Picker, Upload, Signature, and so on) emit the event immediately. For a Multiple Choice or Image Choice option, **ll-quiz-input-click** fires first (the click), then **ll-quiz-value-change** (the resulting value).
* Values set through the LlQuiz API (**block.setValue()**, **block.reset()**) emit the event immediately.
* Values present when the quiz loads (defaults, URL parameters, restored answers) are the starting point, not changes, so they do not emit the event. They are available in **fields** on **ll-quiz-step-view**.
* Nothing is emitted when the new value equals the last reported one.

**Event Detail:**

* **quizId** (string): The unique identifier of the quiz
* **blockId** (string): The unique identifier of the block
* **blockName** (string): The name property of the block (the variable name)
* **blockType** (string): The block type, e.g. `text-field`, `multiple-choice`, `checkbox-field`
* **stepId** (string): The step ID where the block is located
* **stepName** (string): The step name where the block is located
* **value** (string): The new value, in the same format as **Field.value** (multiple selections joined by the block’s separator, a checkbox as `checked` or `unchecked`)
* **previousValue** (string): The value reported by the previous **ll-quiz-value-change** of this block, or the value the block had when the quiz loaded
* **source** (string): Who changed the value:
  * `user`: the visitor
  * `api`: your own script, through the LlQuiz API
  * `system`: the quiz itself (reset on back navigation, clearing the answers after submit)
* **llQuizApi** (LlQuizApi): The LlQuiz API instance for interacting with the quiz

**Example:**

```javascript theme={null}
window.addEventListener('ll-quiz-value-change', (event) => {
    const { quizId, blockName, blockType, stepName, value, previousValue, source, llQuizApi } = event.detail;

    // Ignore changes made by scripts or by the quiz itself
    if (source !== 'user') return;

    console.log(`${blockName} (${blockType}) on step ${stepName}: "${previousValue}" -> "${value}"`);

    // Track answers for analytics
    if (window.dataLayer) {
        window.dataLayer.push({
            'event': 'll_quiz_answer',
            'quiz_id': quizId,
            'block_name': blockName,
            'block_type': blockType,
            'step_name': stepName,
            'value': value
        });
    }

    // Perform custom logic based on the new value
    if (blockName === 'plan' && value === 'premium') {
        llQuizApi.getBlockByName('promo-code').visibility.show();
    }
});
```

## Understanding fields and fieldsSimple

**fields** and **fieldsSimple** contain all information from your quiz in different structures.

**Quick Overview:**

* **fieldsSimple**: A key-value object where keys are field labels and values are user inputs as strings
* **fields**: An array of detailed field objects with complete metadata (id, label, value, key, stepId, stepName)

**Quick Example:**

```json theme={null}
fieldsSimple: {
    "Choose your housing type": "Apartment",
    "Email": "email@example.com",
    "Consent": "true",
},

fields: [
    {
        id: "text-field-123",
        label: "Please enter your name",
        value: "John Doe",
        key: "text-field-123",
        stepId: "step-1",
        stepName: "start"
    }
]
```

## Using LlQuiz API in Events

All events provide access to the **llQuizApi** instance, which allows you to interact with your quiz programmatically.

**Available Methods:**

* **llQuizApi.getCurrentStepID()** – Returns the current step ID (e.g., “step-1”)
* **llQuizApi.getCurrentStepName()** – Returns the current step name (e.g., “start”)
* **llQuizApi.getBlocks()** – Returns all blocks in the quiz
* **llQuizApi.getBlockByID(blockId)** – Returns a specific block by its ID
* **llQuizApi.getBlockByName(blockName)** – Returns a block by its name property (first match)
* **llQuizApi.getBlocksByStepID(stepId)** – Returns all blocks in a specific step
* **llQuizApi.getBlocksByStepName(stepName)** – Returns all blocks in a specific step

**Block Methods:**

Most blocks support:

* **block.getValue()** – Get the current value of the block
* **block.setValue(value)** – Set the value of the block
* **block.reset()** – Reset the block to its initial state

**Example:**

```javascript theme={null}
window.addEventListener('ll-quiz-step-view', (event) => {
    const { llQuizApi } = event.detail;
    
    // Get all blocks in current step
    const currentStepId = llQuizApi.getCurrentStepID();
    const stepBlocks = llQuizApi.getBlocksByStepID(currentStepId);
    
    // Interact with blocks
    stepBlocks.forEach(block => {
        if (block.blockType === 'text-field') {
            const value = block.getValue();
            console.log(`${block.blockID}: ${value}`);
        }
    });
});
```

## Complete Example

Here’s a complete example showing how to use all quiz events together:

```javascript theme={null}
window.addEventListener('ll-quiz-init', (event) => {
    const { quizId, llQuizApi } = event.detail;
    console.log('Quiz initialized:', quizId);
});

window.addEventListener('ll-quiz-step-view', (event) => {
    const { quizId, stepId, stepName, fieldsSimple, llQuizApi } = event.detail;
    console.log(`Quiz: ${quizId}`);
    console.log(`Viewing step: ${stepName} (${stepId})`);
    console.log('Step data:', fieldsSimple);
});

window.addEventListener('ll-quiz-step-leave', (event) => {
    const { quizId, stepName } = event.detail;
    console.log(`Quiz: ${quizId}`);
    console.log(`Leaving step: ${stepName}`);
});

window.addEventListener('ll-quiz-submit', (event) => {
    const { quizId, stepId, stepName, fields, fieldsSimple, response } = event.detail;
    console.log(`Quiz: ${quizId}`);
    console.log(`Quiz submitted from step: ${stepName} (${stepId})`);
    console.log('All quiz data:', fieldsSimple);
    console.log('API response:', response);
    
    // Example: Send to analytics
    if (window.gtag) {
        window.gtag('event', 'conversion', {
            'send_to': 'AW-CONVERSION_ID/CONVERSION_LABEL',
            'value': 1.0,
            'currency': 'USD'
        });
    }
});

window.addEventListener('ll-quiz-exit', (event) => {
    const { quizId, llQuizApi } = event.detail;
    console.log(`Quiz: ${quizId}`);
    console.log('Quiz exited (tab/window closed)');
    
    // Example: Track exit event
    if (window.gtag) {
        window.gtag('event', 'quiz_exit', {
            'quiz_id': quizId
        });
    }
    
    // Note: This event is based on pagehide and may not fire reliably
    // Don't rely on it for critical operations
});

window.addEventListener('ll-quiz-button-click', (event) => {
    const { quizId, blockId, blockName, stepId, stepName, llQuizApi } = event.detail;
    console.log(`Quiz: ${quizId}`);
    console.log(`Button clicked: ${blockName} (${blockId})`);
    console.log(`In step: ${stepName} (${stepId})`);
    
    // Example: Track button clicks
    if (window.gtag) {
        window.gtag('event', 'button_click', {
            'quiz_id': quizId,
            'block_id': blockId,
            'block_name': blockName,
            'step_id': stepId,
            'step_name': stepName
        });
    }
});

window.addEventListener('ll-quiz-input-click', (event) => {
    const { quizId, blockId, blockName, stepId, stepName, optionId, optionValue, optionLabel, llQuizApi } = event.detail;
    console.log(`Quiz: ${quizId}`);
    console.log(`Option clicked: ${optionLabel} (${optionId})`);
    console.log(`In block: ${blockName} (${blockId})`);
    console.log(`In step: ${stepName} (${stepId})`);
    
    // Example: Track option clicks
    if (window.gtag) {
        window.gtag('event', 'option_click', {
            'quiz_id': quizId,
            'block_id': blockId,
            'block_name': blockName,
            'step_id': stepId,
            'step_name': stepName,
            'option_id': optionId,
            'option_value': optionValue,
            'option_label': optionLabel
        });
    }
});

window.addEventListener('ll-quiz-value-change', (event) => {
    const { quizId, blockName, blockType, stepName, value, previousValue, source } = event.detail;
    if (source !== 'user') return; // only the visitor's own answers
    console.log(`Quiz: ${quizId}`);
    console.log(`Answer changed: ${blockName} (${blockType}) on ${stepName}: "${previousValue}" -> "${value}"`);
    
    // Example: Track answers
    if (window.dataLayer) {
        window.dataLayer.push({
            'event': 'll_quiz_answer',
            'quiz_id': quizId,
            'block_name': blockName,
            'step_name': stepName,
            'value': value
        });
    }
});
```
