> ## 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 a API de eventos do quiz para rastreamento e automação

> Reaja ao que acontece no seu quiz: quando ele carrega, quando uma etapa é exibida, quando uma resposta muda, quando a validação falha ou quando o visitante envia o quiz.

Seu quiz anuncia o que acontece por meio de eventos do navegador em `window`. Escute esses eventos para rastrear o comportamento dos visitantes na sua ferramenta de análise, reagir às respostas ou executar seu próprio código no momento certo.

```javascript theme={null}
window.addEventListener('ll-quiz-step-view', (event) => {
  console.log('Visitor is on step', event.detail.stepName);
});
```

Todo evento coloca seus dados em `event.detail`. Duas informações estão sempre presentes:

* `quizId`: qual quiz disparou o evento
* `llQuizApi`: a [API do quiz](/pt-BR/features/quizzes/api/reference), para que você possa ler ou alterar o quiz direto no listener

<Note>
  O `ll-quiz-init` é disparado assim que o quiz fica pronto, o que pode acontecer antes de o seu script rodar. Não se preocupe: um listener registrado depois ainda recebe o `ll-quiz-init`. Todos os outros eventos são disparados por ações do visitante, quando o seu script já está no lugar.
</Note>

## Eventos em resumo

| Evento                          | Quando é disparado                 | Dados úteis                                     |
| :------------------------------ | :--------------------------------- | :---------------------------------------------- |
| `ll-quiz-init`                  | O quiz está pronto                 | `llQuizApi`                                     |
| `ll-quiz-step-view`             | Uma etapa é exibida                | `stepName`, `fields`                            |
| `ll-quiz-step-leave`            | O visitante sai de uma etapa       | `stepName`                                      |
| `ll-quiz-value-change`          | Uma resposta é confirmada          | `blockName`, `value`, `previousValue`, `source` |
| `ll-quiz-input-click`           | Uma opção de escolha é clicada     | `blockName`, `optionLabel`, `optionValue`       |
| `ll-quiz-button-click`          | Um botão é clicado                 | `blockName`                                     |
| `ll-quiz-validation-error`      | A saída de uma etapa foi bloqueada | `errors`, `source`                              |
| `ll-quiz-google-address-select` | Um endereço é selecionado          | `address`                                       |
| `ll-quiz-submit`                | O quiz foi enviado                 | `fields`, `fieldsSimple`, `response`            |
| `ll-quiz-exit`                  | A aba é fechada                    |                                                 |

## ll-quiz-init

É disparado quando o quiz já está na página e pronto. É aqui que você obtém o `llQuizApi`, preenche valores previamente ou faz suas configurações.

<ResponseField name="quizId" type="string" />

<ResponseField name="llQuizApi" type="LlQuizApi">
  A API do quiz para este quiz
</ResponseField>

```javascript theme={null}
window.addEventListener('ll-quiz-init', (event) => {
  const quiz = event.detail.llQuizApi;
  quiz.getBlock('source').setValue('landing-page-a');
});
```

## ll-quiz-step-view

É disparado sempre que uma etapa é exibida, inclusive a primeira, no carregamento, e quando o visitante volta.

<ResponseField name="stepId" type="string" />

<ResponseField name="stepName" type="string" />

<ResponseField name="fields" type="Field[]">
  Respostas dadas até o momento. Veja [fields e fieldsSimple](#fields-e-fieldssimple)
</ResponseField>

<ResponseField name="fieldsSimple" type="object">
  As mesmas respostas no formato rótulo → valor
</ResponseField>

```javascript theme={null}
window.addEventListener('ll-quiz-step-view', (event) => {
  const { stepName, quizId } = event.detail;
  window.dataLayer?.push({ event: 'quiz_step', quiz: quizId, step: stepName });
});
```

## ll-quiz-step-leave

É disparado quando o visitante sai de uma etapa, antes do próximo `ll-quiz-step-view`. Use-o para medir quanto tempo o visitante passou em uma etapa ou para salvar um rascunho.

<ResponseField name="stepName" type="string" />

```javascript theme={null}
let shownAt = Date.now();

window.addEventListener('ll-quiz-step-view', () => {
  shownAt = Date.now();
});

window.addEventListener('ll-quiz-step-leave', (event) => {
  const seconds = Math.round((Date.now() - shownAt) / 1000);
  window.dataLayer?.push({ event: 'quiz_step_time', step: event.detail.stepName, seconds });
});
```

## ll-quiz-value-change

É disparado quando uma resposta é confirmada. Os campos de digitação (text, email, phone, number, textarea, date, birth date, zip code, address, OTP) são confirmados quando o visitante sai do campo ou da etapa, então você recebe um evento por resposta, e não um a cada tecla pressionada. Todas as outras entradas, e todos os valores definidos pela API, são confirmados imediatamente.

<ResponseField name="blockId" type="string" />

<ResponseField name="blockName" type="string">
  O nome do bloco definido no construtor
</ResponseField>

<ResponseField name="blockType" type="string">
  Por exemplo, `text-field` ou `multiple-choice`
</ResponseField>

<ResponseField name="stepId" type="string" />

<ResponseField name="stepName" type="string" />

<ResponseField name="value" type="string">
  A nova resposta, no mesmo formato de `Field.value`
</ResponseField>

<ResponseField name="previousValue" type="string">
  A resposta informada da última vez, ou o valor com que o quiz foi carregado
</ResponseField>

<ResponseField name="source" type="'user' | 'api' | 'system'">
  `user`: o visitante. `api`: o seu script, pela API do quiz. `system`: o próprio quiz, por exemplo ao limpar as respostas depois do envio
</ResponseField>

Nada é disparado quando o valor não muda. Os valores que já existem quando o quiz carrega (valores padrão, parâmetros de URL, respostas restauradas) são o ponto de partida e não disparam o evento; eles estão em `fields` no `ll-quiz-step-view`.

```javascript theme={null}
window.addEventListener('ll-quiz-value-change', (event) => {
  const { blockName, value, source } = event.detail;
  if (source !== 'user') return; // ignore scripted and automatic changes

  window.dataLayer?.push({ event: 'quiz_answer', field: blockName, value });
});
```

## ll-quiz-input-click

É disparado quando o visitante clica em uma opção de um bloco multiple choice ou image choice. Para o mesmo clique, é disparado antes do `ll-quiz-value-change`.

<ResponseField name="blockId" type="string" />

<ResponseField name="blockName" type="string" />

<ResponseField name="stepId" type="string" />

<ResponseField name="stepName" type="string" />

<ResponseField name="optionId" type="string" />

<ResponseField name="optionValue" type="string">
  O valor da opção, como armazenado na resposta
</ResponseField>

<ResponseField name="optionLabel" type="string">
  O texto que o visitante viu
</ResponseField>

```javascript theme={null}
window.addEventListener('ll-quiz-input-click', (event) => {
  const { blockName, optionLabel, optionValue, llQuizApi } = event.detail;

  window.dataLayer?.push({ event: 'quiz_option', field: blockName, option: optionLabel });

  // Show a hint under the plan picker for one option
  if (blockName === 'plan') {
    const hint = llQuizApi.getBlock('planHint');
    optionValue === 'enterprise' ? hint.visibility.show() : hint.visibility.hide();
  }
});
```

## ll-quiz-button-click

É disparado quando um bloco Continue, Previous, Submit ou Button é clicado, antes de qualquer validação. Ele é disparado mesmo quando o clique acaba bloqueado, então conta tentativas, e não sucessos.

<ResponseField name="blockId" type="string" />

<ResponseField name="blockName" type="string" />

<ResponseField name="stepId" type="string" />

<ResponseField name="stepName" type="string" />

```javascript theme={null}
window.addEventListener('ll-quiz-button-click', (event) => {
  const { blockName, stepName } = event.detail;
  window.dataLayer?.push({ event: 'quiz_button', step: stepName, button: blockName });
});
```

<Tip>
  Para saber se o clique realmente levou o visitante adiante, combine-o com o `ll-quiz-step-leave` (levou) ou com o `ll-quiz-validation-error` (não levou).
</Tip>

## ll-quiz-validation-error

É disparado quando uma tentativa de sair de uma etapa é bloqueada porque algo nela está inválido. Você recebe um evento por tentativa, depois que todas as verificações terminam (incluindo as verificações no servidor dos campos de e-mail, telefone e OTP), com a lista exata dos erros que o visitante vê. Blocos ocultos nunca são incluídos.

<ResponseField name="stepId" type="string" />

<ResponseField name="stepName" type="string" />

<ResponseField name="source" type="'user' | 'api' | 'system'">
  `user`: um botão ou uma opção que navega. `api`: o seu script (`validateStep()`, `goNext()`, `goToStep()`, `submit()`). `system`: o quiz tentou avançar sozinho (loader, countdown, pagamento)
</ResponseField>

<ResponseField name="triggerBlockId" type="string">
  O botão ou a opção que iniciou a tentativa; vazio para `api`
</ResponseField>

<ResponseField name="triggerBlockName" type="string">
  Vazio para `api`
</ResponseField>

<ResponseField name="errors" type="array">
  Uma entrada por bloco com erro, na ordem da etapa: `blockId`, `blockName`, `blockType` e `messages` (os textos de erro; o primeiro é o exibido)
</ResponseField>

Ele não é disparado quando a etapa é válida, quando o botão Previous é usado (ele nunca valida) nem em um clique de escolha que não navega.

```javascript theme={null}
window.addEventListener('ll-quiz-validation-error', (event) => {
  const { stepName, errors, llQuizApi } = event.detail;

  // Find out which fields stop visitors
  window.dataLayer?.push({ event: 'quiz_blocked', step: stepName, fields: errors.map((e) => e.blockName) });

  // And help them: move the cursor to the first one
  llQuizApi.getBlock(errors[0].blockId).focus();
});
```

## ll-quiz-google-address-select

É disparado quando o visitante escolhe uma sugestão em um bloco Google Address.

<ResponseField name="blockId" type="string" />

<ResponseField name="blockName" type="string" />

<ResponseField name="stepId" type="string" />

<ResponseField name="stepName" type="string" />

<ResponseField name="address" type="object">
  `street`, `city`, `state`, `stateShort`, `postalCode`, `country`, `countryShort`
</ResponseField>

```javascript theme={null}
window.addEventListener('ll-quiz-google-address-select', (event) => {
  const { address, llQuizApi } = event.detail;
  llQuizApi.getBlock('city').setValue(address.city);
});
```

## ll-quiz-submit

É disparado quando o quiz é enviado, depois que o lead é salvo. É o lugar certo para enviar as respostas para outro sistema ou disparar uma conversão.

<ResponseField name="stepId" type="string">
  A etapa a partir da qual o visitante enviou o quiz
</ResponseField>

<ResponseField name="stepName" type="string" />

<ResponseField name="fields" type="Field[]">
  Todas as respostas
</ResponseField>

<ResponseField name="fieldsSimple" type="object">
  Todas as respostas no formato rótulo → valor
</ResponseField>

<ResponseField name="response" type="any">
  A resposta do servidor do LanderLab, ou `null` quando nenhum lead foi salvo (por exemplo, quando o salvamento de leads está desativado nas configurações do quiz)
</ResponseField>

```javascript theme={null}
window.addEventListener('ll-quiz-submit', (event) => {
  fetch('https://example.com/leads', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(event.detail.fieldsSimple),
  });
});
```

## ll-quiz-exit

É disparado quando a aba ou a janela é fechada ou quando o visitante sai da página, com base no evento `pagehide` do navegador.

<Warning>
  Os navegadores não garantem esse evento em todos os fechamentos. Use-o para um rastreamento de melhor esforço com `navigator.sendBeacon`, nunca para algo que precisa acontecer obrigatoriamente.
</Warning>

```javascript theme={null}
window.addEventListener('ll-quiz-exit', (event) => {
  const { llQuizApi } = event.detail;
  if (llQuizApi.getInfo().isSubmitted) return; // finished visits are not abandonments

  const { name } = llQuizApi.getCurrentStep();
  navigator.sendBeacon('https://example.com/abandoned', JSON.stringify({ lastStep: name }));
});
```

## fields e fieldsSimple

`fields` é uma lista com uma entrada por bloco respondido:

```javascript theme={null}
[
  { id: 'firstName', label: 'First name', value: 'Ada', key: 'firstName', stepId: 'step-…', stepName: 'contact' },
  { id: 'plan', label: 'Plan', value: 'pro', key: 'plan', stepId: 'step-…', stepName: 'plan' },
]
```

`fieldsSimple` traz as mesmas informações em um único objeto, com o rótulo como chave, o que é prático para encaminhar os dados:

```javascript theme={null}
{ 'First name': 'Ada', 'Plan': 'pro' }
```

Os dois deixam de fora blocos ocultos e respostas vazias. Se dois blocos tiverem o mesmo rótulo, `fieldsSimple` junta os valores com uma vírgula. A API do quiz retorna os mesmos formatos em `getAnswers()` e `getAnswersSimple()`.
