O duxt comunica o que os leitores fazem com um site de documentação —
pesquisar, copiar um comando, experimentar um endpoint, responder «Esta página
foi útil?» — a **uma única função que escreves**. Não traz nenhum fornecedor,
nenhum SDK e nenhum script, e um site que não tenha escrito essa função não
comunica nada nem descarrega seja o que for a mais.

::callout{type="info" title="Desligado até o ligares"}
Não há destino por omissão, porque uma camada de documentação não pode escolher
um para os leitores de outra pessoa. Sem `duxt.analytics.track`, cada uma das
chamadas abaixo chega a uma função ausente e para por aí.
::

## Passos

::steps

1. **Escreve o callback.** Vive em `app.config.ts`, ao lado do resto da tua
   configuração do duxt, e recebe um evento por cada interação:

   ```ts [app/app.config.ts]
   export default defineAppConfig({
     duxt: {
       analytics: {
         track(event) {
           // `event.name` é o discriminante; `event.context` diz em que página,
           // locale, fonte e versão isto aconteceu.
           console.log(event.name, event.context.path);
         }
       }
     }
   });
   ```

   O callback corre **apenas no browser**. Uma compilação e uma pré-renderização
   nunca o chamam, por isso uma renderização estática não te enche a analítica
   com páginas que um rastreador abriu.

2. **Envia-o para onde a tua analítica já vive.** O que quer que o teu
   fornecedor exponha — um SDK que já esteja na página, ou uma rota tua para que
   o browser do leitor nunca fale com um terceiro que não escolheste:

   ```ts [app/app.config.ts]
   export default defineAppConfig({
     duxt: {
       analytics: {
         track(event) {
           const { name, context, ...properties } = event;

           // O teu fornecedor, os teus nomes de propriedades, a tua barreira de
           // consentimento.
           window.plausible?.(name, { props: { ...context, ...properties } });
         }
       }
     }
   });
   ```

   ::callout{type="warning" title="O consentimento é teu, não do duxt"}
   O duxt não define nenhum cookie, não guarda nada, não retém nada e não mostra
   nenhum aviso de consentimento — não tem nada por que perguntar, porque nada
   sai da página a não ser através da tua função. Isso também quer dizer que **a
   barreira é tua**: se a tua política de privacidade exigir consentimento antes
   de isto chegar a um fornecedor, verifica-o dentro do `track` e sai cedo.
   ::

3. **Escolhe os eventos que queres e deixa cair os restantes.** A união é
   fechada, por isso um `switch` cobre-a de forma exaustiva e tudo o que não
   nomeares simplesmente não é enviado:

   ```ts [app/app.config.ts]
   track(event) {
     if (event.name === 'search' && event.results === 0) {
       // O único relatório que um site de documentação quase sempre quer: um
       // termo que alguém procurou e a que o site não soube responder.
       report('docs-search-miss', { query: event.query, ...event.context });
     }
   }
   ```

4. **Verifica que chega um evento**, com o contexto que esperavas — sob um
   prefixo de versão e de locale, e não apenas no URL nu.

::

## Os eventos

Cada evento tem um `name`, os seus próprios campos e um `context`.

| `name` | Emitido quando | Transporta |
| :--- | :--- | :--- |
| `search` | Uma consulta não vazia assenta, depois do debounce — incluindo uma que não encontrou nada | `query`, `results`, `approximate` |
| `search-result` | Um leitor abre um resultado | `query`, `rank`, `to`, `collection` |
| `copy` | Um exemplo de código da camada é copiado | `kind`, `language`, `manager`, `sample` |
| `api-request` | Um pedido do cliente de ensaio termina | `operation`, `method`, `path`, `outcome`, `statusClass`, `duration` |
| `feedback` | Um leitor responde a «Esta página foi útil?» | `helpful` |

`search` dispara **uma vez por consulta assente**, não por tecla premida: o
debounce descarta o que ninguém acabou de escrever, e um resultado substituído
por outro mais recente nunca é comunicado, porque o leitor nunca chegou a vê-lo.

`copy` cobre os exemplos de código da própria camada — uma cerca, um
`::code-group`, um bloco `::package-managers`, uma amostra de pedido no cliente
de ensaio — com `kind` a dizer qual. **«Copiar a página como Markdown» não
pertence a esta família** e não emite nada: é a página, não um exemplo dentro
dela.

`api-request` descreve a operação **tal como o documento OpenAPI a declara**.
`path` é o modelo (`/pets/{id}`), nunca o URL que foi chamado.

### O contexto

| Campo | Notas |
| :--- | :--- |
| `path` | O caminho da documentação, sem o prefixo de locale, a query string nem o fragmento |
| `locale` | O locale em que a página foi lida |
| `source` | De que fonte veio a página — ausente num site com uma só fonte |
| `version` | Que versão — ausente onde a fonte só tem uma |

## O que nunca é enviado

Esta lista é o sentido da funcionalidade, por isso vale a pena dizê-la sem
rodeios. Nenhum evento transporta:

- uma credencial, um cabeçalho ou um token de API;
- um corpo de pedido ou de resposta, nem um URL de pedido concreto;
- o texto que foi copiado;
- o conteúdo apresentado de um resultado de pesquisa;
- um identificador de browser, de sessão ou de leitor, seja de que tipo for;
- a query string ou o fragmento do caminho da própria página.

O duxt também nunca **transmite, retém nem persiste** nada por si. Não há fila,
nem repetição, nem armazenamento, nem chamada de rede na camada: a tua função é
a única coisa que alguma vez sai da página.

O teu callback nunca é esperado, e o que quer que ele lance ou com que rejeite é
engolido — um fornecedor em baixo não pode levar consigo a pesquisa, a cópia, a
opinião ou o pedido.

## Opiniões da página, pelos dois caminhos

`feedback` é a mesma resposta que o `DuxtPageFeedback` sempre emitiu. O evento
`@feedback` do componente e o seu slot por omissão não mudaram, por isso
[envolvê-lo](/guides/collect-page-feedback) continua a funcionar e nenhum dos
caminhos precisa do outro — usa o callback de analítica se quiseres um destino
único para tudo, e o invólucro se só as opiniões forem para um sítio próprio.

## Lista de verificação

- [ ] `duxt.analytics.track` está definido, e não foi preciso mais nada para o ligar
- [ ] O destino é teu — um fornecedor que escolheste, ou uma rota tua
- [ ] O consentimento é verificado dentro do `track`, se a tua política o pedir
- [ ] Chegou um evento com o caminho, o locale, a fonte e a versão que esperavas
- [ ] Nada do que reencaminhas identifica o leitor