# @clickmax/browser-sdk

SDK de navegador da Clickmax para captura pública de leads.

Ele foi feito para dois cenários:

- você quer colar **um script** no site e deixar a Clickmax cuidar do formulário
- você já tem seu próprio formulário e quer usar apenas **uma função JS** para enviar o lead

## Como escolher

### Quero a forma mais simples

Use o bundle via script tag.

Bom para:

- landing pages
- Webflow
- WordPress
- sites estáticos
- integrações rápidas

### Já tenho meu frontend

Use `submitLead()` via `@clickmax/browser-sdk/forms`.

Bom para:

- apps próprios
- formulários customizados
- fluxos em que sua UI já existe

## Modo 1: Script Tag

O bundle global inclui:

- widget renderizado
- bind de formulários existentes
- modal
- auto-init
- estilos padrão

<details>
<summary>Além disso, ao carregar o script, a API global <code>window.Clickmax.submitLead(...)</code> também fica
disponível. Isso é útil quando você quer continuar usando o bundle global, mas prefere controlar o
envio manualmente em vez de depender do submit padrão do formulário.</summary>

```html
<script
  src="https://cdn.jsdelivr.net/npm/@clickmax/browser-sdk@latest/dist/forms/clickmax-forms.js"
  defer
></script>

<script>
  async function sendLead() {
    await window.Clickmax.submitLead({
      slug: "abc123",
      data: {
        email: "lead@example.com",
        name: "Maria",
      },
    });
  }
</script>
```

</details>

### Widget inline

```html
<script
  src="https://cdn.jsdelivr.net/npm/@clickmax/browser-sdk@latest/dist/forms/clickmax-forms.js"
  defer
></script>

<div
  data-cx-form-widget
  data-cx-slug="abc123"
  data-cx-mode="inline"
  data-cx-theme="light"
  data-cx-accent="#111827"
  data-cx-title="Fale com nosso time"
  data-cx-description="Deixe seus dados e entraremos em contato."
></div>
```

### Widget em modal

```html
<script
  src="https://cdn.jsdelivr.net/npm/@clickmax/browser-sdk@latest/dist/forms/clickmax-forms.js"
  defer
></script>

<button data-cx-open="form-contato">Abrir formulário</button>

<div
  data-cx-form-widget
  data-cx-widget-id="form-contato"
  data-cx-slug="abc123"
  data-cx-mode="modal"
  data-cx-title="Solicite contato"
></div>
```

### Usando seu próprio HTML

Se você quer manter seu markup, o script também consegue conectar formulários existentes:

```html
<script
  src="https://cdn.jsdelivr.net/npm/@clickmax/browser-sdk@latest/dist/forms/clickmax-forms.js"
  defer
></script>

<form
  data-cx-ingest-form
  data-cx-slug="abc123"
  data-cx-success-message="Enviado com sucesso!"
>
  <input data-cx-field="name" placeholder="Seu nome" />
  <input data-cx-field="email" placeholder="Seu e-mail" />
  <input data-cx-field="telephone" placeholder="Seu telefone" />
  <input type="checkbox" data-cx-field="lgpdApproved" />
  <input type="text" data-cx-field="website" hidden />
  <button type="submit">Enviar</button>
</form>
```

O `data-cx-field` pode ficar no próprio `<input>` ou em um elemento pai/wrapper próximo.
Isso ajuda em builders como Framer, onde o atributo customizado costuma ser aplicado no contêiner do campo em vez do controle nativo.

Se o seu builder também registra listeners próprios de `submit` e você quer que a SDK assuma o envio sozinha, adicione `data-cx-hijack-form` no `<form>`.
Nesse modo, a SDK registra o listener em capture phase e interrompe outros listeners de `submit` do mesmo fluxo.

Se você quiser levar os dados já preenchidos para a próxima página no redirect, adicione `data-cx-redirect-with-query`.
Nesse modo, a SDK acrescenta `name`, `email`, `phone`, `utm_source`, `utm_medium`, `utm_campaign`, `utm_content` e `utm_term` na query string final.

### Meio-termo: comportamento da SDK com sua própria estilização

Se você quer manter o comportamento em JavaScript da SDK, mas prefere não usar os estilos dela,
adicione `data-cx-nostyles`.

Esse modo mantém:

- submit
- validação
- redirect
- success/error
- comportamento de modal

Mas deixa de aplicar as classes visuais da SDK.

```html
<script
  src="https://cdn.jsdelivr.net/npm/@clickmax/browser-sdk@latest/dist/forms/clickmax-forms.js"
  defer
></script>

<form
  data-cx-ingest-form
  data-cx-slug="abc123"
  data-cx-nostyles
  data-cx-success-message="Enviado com sucesso!"
>
  <input data-cx-field="name" placeholder="Seu nome" />
  <input data-cx-field="email" placeholder="Seu e-mail" />
  <input data-cx-field="telephone" placeholder="Seu telefone" />
  <button type="submit">Enviar</button>
</form>
```

## Modo 2: API JavaScript

Use esse modo quando a sua interface já existe e você quer controlar tudo por conta própria.

```ts
import { submitLead } from "@clickmax/browser-sdk/forms";

await submitLead({
  slug: "abc123",
  data: {
    email: "lead@example.com",
    name: "Lead Example",
    telephone: "5511999999999",
  },
});
```

### Exemplo com tratamento de erro

```ts
import { submitLead } from "@clickmax/browser-sdk/forms";

try {
  await submitLead({
    slug: "abc123",
    data: {
      email: "lead@example.com",
      name: "Maria",
    },
  });

  console.log("Lead enviado com sucesso");
} catch (error) {
  console.error("Não foi possível enviar o lead", error);
}
```

## Atributos suportados

| Atributo                            | Onde usar                                  | Descrição                                                                   |
| ----------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------- |
| `data-cx-slug`                      | Formulários existentes, widget renderizado | Slug público do ingest link.                                                |
| `data-cx-api-url`                   | Formulários existentes, widget renderizado | Override opcional da base da API.                                           |
| `data-cx-nostyles`                  | Formulários existentes, widget renderizado | Mantém o comportamento JS sem aplicar classes visuais da SDK.               |
| `data-cx-hijack-form`               | Formulários existentes                     | Faz a SDK assumir exclusivamente o submit do form.                          |
| `data-cx-redirect-url`              | Formulários existentes, widget renderizado | Redirect local configurado no HTML. Tem prioridade sobre o redirect do CRM. |
| `data-cx-redirect-with-query`       | Formulários existentes, widget renderizado | Acrescenta `name`, `email`, `phone` e as UTM da página na query string do redirect final. |
| `data-cx-success-message`           | Formulários existentes, widget renderizado | Mensagem exibida após envio com sucesso.                                    |
| `data-cx-reset-on-success`          | Formulários existentes, widget renderizado | Reseta o form após sucesso quando ativo.                                    |
| `data-cx-locale`                    | Formulários existentes, widget renderizado | Localização usada pela SDK (`pt-BR` ou `en`).                               |
| `data-cx-mode="inline\|modal"`      | Widget renderizado                         | Define se o widget abre inline ou em modal.                                 |
| `data-cx-widget-id`                 | Widget renderizado                         | Identificador usado pelos gatilhos `data-cx-open`.                          |
| `data-cx-theme="light\|dark\|auto"` | Widget renderizado                         | Tema visual do widget.                                                      |
| `data-cx-accent`                    | Widget renderizado                         | Cor principal do widget.                                                    |
| `data-cx-title`                     | Widget renderizado                         | Título do widget.                                                           |
| `data-cx-description`               | Widget renderizado                         | Descrição do widget.                                                        |
| `data-cx-submit-label`              | Widget renderizado                         | Texto do botão de submit.                                                   |
| `data-cx-fields`                    | Widget renderizado                         | Lista CSV dos campos renderizados.                                          |
| `data-cx-required-fields`           | Widget renderizado                         | Lista CSV dos campos obrigatórios.                                          |
| `data-cx-show-lgpd`                 | Widget renderizado                         | Exibe o checkbox LGPD.                                                      |
| `data-cx-lgpd-required`             | Widget renderizado                         | Torna o checkbox LGPD obrigatório.                                          |

## Campos suportados no form

| Atributo                       | Onde usar                              | Descrição                  |
| ------------------------------ | -------------------------------------- | -------------------------- |
| `data-cx-field="name"`         | Input, select, textarea ou wrapper pai | Mapeia o nome do lead.     |
| `data-cx-field="email"`        | Input, select, textarea ou wrapper pai | Mapeia o e-mail do lead.   |
| `data-cx-field="telephone"`    | Input, select, textarea ou wrapper pai | Mapeia o telefone do lead. |
| `data-cx-field="lgpdApproved"` | Input checkbox ou wrapper pai          | Mapeia a aprovação LGPD.   |
| `data-cx-field="website"`      | Input hidden ou wrapper pai            | Honeypot anti-spam.        |

O atributo pode estar no campo nativo ou em um wrapper pai, desde que esse wrapper envolva o input/select/textarea correspondente.

## O que o script faz automaticamente

Quando você usa o bundle global, ele inicializa apenas estes seletores:

- `[data-cx-form-widget]`
- `form[data-cx-ingest-form]`

Em páginas CSR, como Framer, ele também observa o DOM e inicializa esses mesmos seletores quando eles aparecerem depois do carregamento inicial.

Ou seja: nada de comportamento implícito fora do que estiver marcado explicitamente.

## Comportamentos importantes

### UTM

- os parâmetros UTM da página são enviados junto com o lead quando presentes

### Anti-spam

- o campo `website` funciona como honeypot
- se ele vier preenchido, o envio é ignorado

### Redirect

- você pode configurar redirect via `data-cx-redirect-url`
- se esse atributo não existir, a SDK usa o `redirectUrl` configurado no ingest link do CRM
- quando os dois existirem, `data-cx-redirect-url` tem prioridade
- por padrão não adicionamos parâmetros sensíveis na URL

## Quando usar cada abordagem

Use **script tag** quando:

- quer colocar para rodar rápido
- quer usar o widget pronto
- quer reaproveitar HTML simples sem escrever JS

Use **submitLead()** quando:

- seu app já controla validação, loading e erros
- você quer integrar com sua própria UI
- você não quer nenhum comportamento automático de DOM

## Tracking

Além dos formulários, a SDK publica um bundle independente de **tracking** que dispara eventos
anônimos (clicks em botões, submits, scroll, visibilidade, page view) para o pages-server da
Clickmax. Funciona em páginas externas (Webflow, WP, sites estáticos) e não depende do bundle de forms.

```html
<script
  src="https://cdn.jsdelivr.net/npm/@clickmax/browser-sdk@latest/dist/tracking/clickmax-tracking.js"
  data-cx-api-url="https://api.clickmax.io/tracking"
  data-cx-track-clicks
  data-cx-track-scroll="25,50,75,90"
  data-cx-track-visibility
  data-cx-pixel-fb
  defer
></script>
```

### Atributos do script

| Atributo                   | Default     | Descrição                                                               |
| -------------------------- | ----------- | ----------------------------------------------------------------------- |
| `data-cx-api-url`          | same-origin | Base URL do pages-server. Obrigatório para páginas externas.            |
| `data-cx-track-clicks`     | ligado      | Captura clicks em `.cm-checkout-button, [data-cx-track="click"]`.       |
| `data-cx-track-scroll`     | desligado   | Thresholds de scroll em %, separados por vírgula (ex.: `25,50,75,90`).  |
| `data-cx-track-visibility` | desligado   | Dispara eventos ao entrar na viewport (`[data-cx-track="visibility"]`). |
| `data-cx-pixel-fb`         | desligado   | Ecoa eventos para o Facebook Pixel se `fbq` estiver presente.           |

### O que é enviado

Cada evento vira um `POST` (via `navigator.sendBeacon` com fallback para `fetch keepalive`) com
`Content-Type: application/vnd.clickmax.tracking+json`. Bots são descartados no servidor.

### Forms + Tracking em um único script

Se você quer forms e tracking na mesma página, dá para carregar os dois bundles em uma
única requisição usando o endpoint `combine` do jsDelivr:

```html
<script
  src="https://cdn.jsdelivr.net/combine/npm/@clickmax/browser-sdk@latest/dist/forms/clickmax-forms.js,npm/@clickmax/browser-sdk@latest/dist/tracking/clickmax-tracking.js"
  data-cx-api-url="https://api.clickmax.io/tracking"
  data-cx-track-clicks
  defer
></script>
```

Os atributos `data-cx-*` do tracking continuam funcionando normalmente na própria tag
combinada. Os bundles são independentes (`window.Clickmax` para forms,
`window.ClickmaxTracking` para tracking) e não colidem.

Use bundles separados quando a página precisa **apenas** de tracking — o bundle de forms
traz CSS e ~13 KB extras que não serão usados.

### Seletores reconhecidos

| Seletor                        | Evento            |
| ------------------------------ | ----------------- |
| `.cm-checkout-button`          | `button_click`    |
| `[data-cx-track="click"]`      | `button_click`    |
| `.cm-next-funnel-node`         | `link_click`      |
| `[data-cx-track="link"]`       | `link_click`      |
| `form.cm-form` (submit)        | `form_submit`     |
| `[data-cx-track="visibility"]` | `element_visible` |
