No navegador: formulário, pixel, chat e push

Embed de formulário, pixel de analytics, chat, web push e o SDK @asender/pages-sdk: o que colar no site e que chave usar.

No navegador: formulários, pixel, chat e push

Tudo o que o Asender coloca no site do seu cliente roda no navegador do visitante: o formulário incorporado, o pixel de analytics, o chat do atendimento e o Web Push. Este guia mostra cada peça: o código para colar, o que ela envia, onde ela guarda dados no navegador e o que liberar na Content-Security-Policy (CSP) do seu site.

Nenhuma dessas peças usa a sua API key. O código de navegador é público: ele carrega só identificadores públicos (o id do formulário, a credencial assinada do pixel, uma chave de site pk_). Nunca cole uma chave sk_ em página de site. Para enviar leads a partir do seu servidor, veja o guia da API de Páginas.

Hosts públicos

HostPara que serve
https://embed.asender.netFormulário incorporado: embed.js, envio, carimbo anti-spam, eventos do funil e a consulta de endereço por CEP. É o endereço que o painel gera nos snippets novos.
https://sites.asender.netRuntime das páginas: pixel.js, /collect, /replay, chat.js e as rotas do formulário (envio, carimbo, eventos e a consulta de endereço, /f/{formID}/endereco). Snippets antigos de formulário, colados com sites., continuam funcionando.
https://api.pages.asender.netPainel e API de Páginas: criar pixels e ler relatórios (exige sessão).
https://api.atendimento.asender.netAPI pública do chat (/public/v1/chat).
https://api.asender.netAPI da plataforma; recebe o registro de Web Push (/v1/push/site/devices).

O domínio asender.com.br segue respondendo em todos esses nomes (embed.asender.com.br, sites.asender.com.br e assim por diante). Snippet já colado com ele continua valendo. Se você tem CSP, libere os dois domínios enquanto houver snippet antigo.

1. Formulário incorporado

Colar em uma linha

No painel de Páginas, abra Formulários, escolha o formulário e clique em Ver como usar. O painel mostra o código pronto e a aba JavaScript é a recomendada:

<script src="https://embed.asender.net/f/frm_0123456789abcdef/embed.js" async></script>

frm_0123456789abcdef é o id do formulário (formID). Ele aparece no código copiado e na URL de envio do bloco API, na mesma tela. O id é público: quem abre o código-fonte da sua página o vê. A proteção da conta é a lista de sites autorizados (veja abaixo), não o sigilo do id.

O embed.js injeta o formulário no lugar da própria tag <script>, sempre com a definição atual. Edite os campos no painel e o site passa a mostrar a versão nova em até 1 minuto, sem recolar nada. O custo é depender de JavaScript. Quem precisa do formulário sem JavaScript usa a aba HTML completo, que é o mesmo formulário escrito por extenso (e que fica "congelado": cada campo novo exige recolar o código).

O que o HTML gerado contém

O <form> é um formulário nativo que posta direto no Asender; o JavaScript só aprimora. Os atributos que o painel escreve nele:

AtributoValorPara que serve
actionhttps://embed.asender.net/f/{formID}Para onde o envio vai.
data-asender-formo formIDIdentifica o formulário. É o que o pixel lê (seção 2).
data-asender-carimbohttps://embed.asender.net/f/{formID}/carimboEndereço do carimbo de tempo anti-spam. As rotas /eventos e /endereco são derivadas dele.
data-asender-sucessotextoMensagem de agradecimento (a configurada no formulário; padrão "Obrigado! Recebemos seus dados.").
data-asender-destinoURL (opcional)Para onde mandar o visitante depois do envio.

Esses atributos são gerados a partir da configuração do formulário no painel (mensagem e destino pós-envio). Você muda o texto e o destino no painel, não no HTML. Na resposta do envio, o servidor manda o pós-envio atual (pos_envio) e o JavaScript o prefere aos atributos; os atributos são o plano B. O redirecionamento só segue destino http:// ou https://.

Como o envio funciona: POST /f/{formID}

Sem credencial. A conta é resolvida pelo próprio formID.

curl -X POST 'https://embed.asender.net/f/frm_0123456789abcdef' \
  -H 'Origin: https://www.seusite.com.br' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'nome=Fulana' \
  --data-urlencode 'email=fulana@exemplo.test' \
  --data-urlencode 'consentimento=on'
# → 200 { "ok": true, "lead_id": "…", "duplicada": false,
#         "pos_envio": { "destino": "", "mensagem": "Obrigado! Recebemos seus dados." } }

O que vale saber:

{
  "error": { "message": "submissão recusada: [email: obrigatório]" },
  "erro": "dados inválidos",
  "campo": "email",
  "motivo": "obrigatório",
  "motivos": ["email: obrigatório"]
}
StatusQuando
200Aceito, deduplicado ou descartado como spam (ok: true).
403Origem fora da lista de sites autorizados do formulário.
404Formulário inexistente.
422Dado inválido ou campo obrigatório ausente (corpo acima).
502 / 503Falha nossa ao registrar ou ao resolver o formulário; tente de novo.

Consentimento (LGPD)

Se o formulário exige consentimento, o HTML inclui uma caixa consentimento obrigatória, com o texto de aceite que você configurou no formulário. O servidor confere: sem a caixa marcada o envio é recusado com 422 (consentimento: obrigatório). A decisão de consentimento e o texto aceito acompanham o lead até o CRM. Se você monta o HTML à mão, mande o campo consentimento com qualquer valor não vazio somente quando a pessoa marcou a caixa.

Anti-spam

Todo formulário gerado leva um campo-isca oculto (_asender_website, que deve ficar vazio) e dois campos de sinal (_asender_carimbo e _asender_interacao). Ao carregar, o script pede GET /f/{formID}/carimbo, que devolve {"carimbo": "…"}: o instante assinado em que o formulário foi aberto. Preencher rápido demais, sem interação, ou tocar na isca soma pontos de suspeita. Não há CAPTCHA. O servidor só descarta quando a soma passa do corte, e um sinal sozinho quase nunca descarta. Sem JavaScript os sinais vão vazios e o servidor os trata como "não medidos".

Preenchimento de endereço por CEP

Se o formulário tem o bloco de endereço, o script consulta GET /f/{formID}/endereco?pais=BR&cep=01310100 e preenche estado, cidade, bairro e rua. A rota só atende formulários que têm endereço e países que eles aceitam; responde 404 (CEP ou campo inexistente), 422 (país ou CEP inválido), 429 (muitas consultas) ou 503. Nenhuma dessas respostas trava o formulário: o visitante digita o endereço à mão.

O host embed.asender.net também encaminha /f/{formID}/endereco, então o preenchimento por CEP funciona com o snippet apontando para ele. Em instalação cuja borda ainda não recebeu essa atualização, o endereço cai em modo manual.

Eventos no navegador

O formulário dispara eventos que você pode escutar na sua página.

EventoOnde disparadetail
asender:submissaoNo <form>, subindo (bubbles) até document{ id, formulario_id }
asender:enviadoNo <form>{}
asender:erroNo <form>{ campo } (nome do campo com problema, ou vazio)

asender:submissao sai depois de um envio aceito via fetch que devolveu lead_id, e antes de qualquer redirecionamento. Spam e respostas sem lead_id não disparam o evento. O mesmo valor fica em window.asenderSubmissao. O id é o mesmo identificador que o servidor usa como event_id ao reportar a conversão às APIs de anúncio (Meta, Google Ads, TikTok). Por isso você deduplica o pixel do navegador com a conversão do servidor usando esse id como eventID:

<script>
  document.addEventListener("asender:submissao", function (e) {
    // Meta Pixel: mesmo event_id que o servidor manda à API de Conversões
    fbq("track", "Lead", {}, { eventID: e.detail.id });
  });
</script>

asender:enviado e asender:erro não sobem até document; escute no próprio formulário (form.addEventListener(...)). No envio nativo (sem JavaScript) a página não fica aberta, então nenhum desses eventos acontece.

2. Pixel de analytics

O pixel mede o comportamento na página: visita, rolagem, cliques, formulário visto, iniciado e enviado, tempo na página e saída. Ele é opcional; o formulário incorporado funciona e é contado sem ele (veja "Formulário sem pixel").

Criar e instalar

  1. No painel de Páginas, abra Analytics → Pontos de coleta e crie um ponto de coleta (o pixel). Na API, POST https://api.pages.asender.net/v1/pixels (com sessão) devolve o snippet pronto.
  2. Em Domínios autorizados do pixel, cadastre o domínio do seu site (por exemplo www.seusite.com.br). Enquanto ele não estiver na lista, o navegador do visitante recebe 403 e nenhum evento sai.
  3. Cole o snippet antes de </head>.

Num site que não é do Asender, o snippet deve ficar assim:

<script src="https://sites.asender.net/pixel.js"
        data-lz="<credencial-assinada>"
        data-lz-collect="https://sites.asender.net/collect"
        data-lz-replay="1"
        data-lz-replay-url="https://sites.asender.net/replay"
        async></script>
Endereço absoluto. O snippet que o painel e a API (POST /v1/pixels) geram já traz src, data-lz-collect e data-lz-replay-url com o endereço público do runtime. Se você colou um snippet antigo, com src="/pixel.js" relativo, ele aponta para o seu próprio domínio e não carrega: troque pelo snippet acima ou gere o código de novo. Como reforço, o pixel.js também aceita data-base (a origem do runtime) e, sem ele, usa a origem do próprio src para /collect e /replay. Em páginas publicadas pelo próprio Asender nada disso é necessário.
AtributoPara que serve
data-lzA credencial assinada do ponto de coleta (identifica conta e pixel; não é segredo). Sem ela o script não faz nada.
data-lz-collectEndereço de /collect. Padrão: /collect na origem do src do script (ou de data-base).
data-lz-replay1 liga a gravação de jornada (veja abaixo). Ausente, nada é gravado.
data-lz-replay-urlEndereço de /replay. Padrão: /replay na origem do src do script (ou de data-base).
data-baseOrigem do runtime (ex.: https://sites.asender.net) para /collect e /replay. Padrão: a origem do src.
data-lz-clickEm qualquer elemento seu: o texto que vira o nome do clique no relatório.

O que ele coleta

O script manda lotes de eventos para POST /collect (JSON, com a credencial no corpo). Eventos: page_view, scroll_depth (25, 50, 75 e 100%), click (apenas em links, botões e elementos com data-lz-click, com posição em porcentagem da página), form_view, form_start, form_submit, time_on_page e exit. A sessão é um id aleatório guardado em sessionStorage (chave _lz_s), que morre quando a aba fecha. Sem cookie, sem e-mail, sem nome, sem fingerprint.

Formulários: o atributo data-asender-form

O pixel procura na página os <form data-asender-form="…"> e emite:

Cada evento leva o formID, e é isso que agrupa os números por formulário no relatório. Como o HTML gerado já traz data-asender-form, nenhum passo extra é necessário. Se você monta o HTML à mão, escreva o atributo com o id do formulário (o nome antigo data-form-id ainda é aceito).

Formulário sem pixel

Um formulário incorporado em site sem o pixel também aparece no Analytics geral. O script do próprio formulário manda o funil dele para POST /f/{formID}/eventos, e o servidor espelha três eventos (form_view, form_start, form_submit) no Analytics geral, marcados com origem embed e o host do site. Se o script detecta que o pixel está na página (script[data-lz]), o espelho não acontece, para não contar em dobro.

Gravação de jornada (/replay)

Com data-lz-replay="1", o pixel grava a sequência de interações: clique (seletor do elemento e posição), campo tocado, rolagem, navegação e tamanho da janela. Não é gravação de tela nem de DOM. Em campos de formulário, registra apenas o tipo do campo e o comprimento do valor em faixas (0, 3, 8, 16, 32, 64), nunca o texto digitado, e só quando o campo perde o foco, nunca por tecla. Campos de senha, cartão, CPF/CNPJ e semelhantes (pelo nome ou id) saem como "sensível" e sem comprimento. O seletor traz só tag, id e duas classes. Para ler as jornadas: GET /v1/replay/sessions e .../sessions/{id}/events na API de Páginas (exige sessão).

Como o snippet do painel já inclui data-lz-replay="1", a gravação de jornada vem ligada. Para desligar, remova o atributo. Veja "Privacidade" no fim.

3. Chat do atendimento

O widget de chat abre uma conversa do visitante direto na caixa de entrada do Atendimento.

Instalar

  1. No Atendimento, abra Bot com IA, seção Widget de chat, informe as origens do site (até 10, como https://www.seusite.com.br) e copie o snippet. O painel gera a chave de site pk_chat_… a partir das origens.
  2. Cole antes de </body>:
<script type="module" async
        src="https://sites.asender.net/chat.js"
        data-site-key="pk_chat_…"
        data-base="https://api.atendimento.asender.net"></script>
AtributoObrigatórioPara que serve
srcsimO widget, servido por sites.asender.net/chat.js.
data-site-keysimA chave de site pk_chat_…. Sem ela o widget não monta e escreve um aviso no console.
data-basesimA API do chat (https://api.atendimento.asender.net). Sem ele o widget não monta e escreve um aviso no console: a origem do src é o host de sites, que não é a API do chat.
data-titulonãoTítulo do painel do chat.
data-saudacaonãoPrimeira mensagem de boas-vindas.
data-intervalo-msnãoIntervalo (ms) da busca de novas mensagens quando a conexão ao vivo (SSE) não está disponível. Padrão: 4000.
data-manualnãoPresente, desliga a montagem automática (para quem chama montarChat por conta própria).
data-asender-chatnãoMarca a tag como a do widget quando o src não é idêntico ao do snippet (por exemplo, atrás de proxy).

Cor, título, saudação e posição do widget vêm da aparência salva na tela do Widget, que o script lê ao montar. Os atributos data-titulo e data-saudacao sobrescrevem texto na instalação.

Segurança da chave de site

A chave de site é pública: ela está no código-fonte da página. A defesa é a lista de origens assinada dentro dela, conferida no servidor a cada chamada, mais o limite de frequência por chave. Ela só abre o chat; não vale para nenhuma outra API. Mudou o domínio do site? Gere a chave de novo com as origens novas.

Na primeira mensagem, o servidor grava o cookie asender_chat: um token aleatório, HttpOnly, Secure, SameSite=None, válido por 30 dias e restrito ao caminho /public/v1/chat (é enviado só às rotas do chat, nunca a outras). É ele que reencontra a conversa quando a pessoa volta ao site. Como o widget fala com um domínio diferente do seu site, é um cookie de terceiro; navegadores configurados para bloquear cookies de terceiros podem impedir que a conversa seja retomada.

4. Web Push

Web Push envia notificações a quem aceitou receber, mesmo com a aba fechada. O seu site registra o navegador do visitante no Asender; as campanhas saem depois, pela ferramenta de Push.

Passo a passo

  1. No app de Push, abra Coletar inscrições, informe as origens do site (de 1 a 10) e gere o pacote. Ele traz quatro itens: a chave de site pk_push_…, o service worker asender-sw.js, o manifest e o snippet de inscrição. A chave de site vale só para as origens informadas.
  2. Salve o service worker como /asender-sw.js na raiz do site. Um service worker só controla o diretório em que é servido; num subdiretório ele não recebe push do site inteiro.
  3. Salve o manifest como /manifest.json e referencie com <link rel="manifest" href="/manifest.json">. Coloque também os ícones /icon-192.png e /icon-512.png, que o manifest e as notificações usam.
  4. Cole o snippet em uma tag <script> e chame asenderSubscribePush() a partir de um clique do visitante. Os navegadores recusam o pedido de permissão disparado no carregamento da página.
  5. O site precisa estar em HTTPS (localhost é a única exceção).

O snippet faz, em ordem: verifica suporte a service worker e a PushManager; pede a permissão de notificação (Notification.requestPermission()); registra /asender-sw.js; assina o push com a chave pública VAPID da sua conta; e envia a inscrição ao Asender:

curl -X POST 'https://api.asender.net/v1/push/site/devices?site_key=pk_push_…' \
  -H 'Origin: https://www.seusite.com.br' \
  -H 'Content-Type: application/json' \
  -d '{ "Endpoint": "https://…", "P256dh": "…", "Auth": "…" }'
# → 200 { "Status": "registered" }

A chave de site vai na query porque o preflight do navegador (a requisição OPTIONS prévia) não leva cabeçalhos próprios: assim a chave e a origem já são conferidas antes do POST existir.

StatusQuando
200Inscrição registrada (Status: "registered").
400Corpo inválido (o endpoint precisa ser https; P256dh e Auth obrigatórios; campo extra é recusado).
401Chave ausente ou inválida. Uma chave de servidor sk_ apresentada aqui também é recusada.
403Origin ausente ou não declarada na chave; ou conta suspensa.
429Limite de frequência por chave e por IP.

Permissões e o que esperar do navegador

Em páginas publicadas pelo próprio Asender com a coleta de push ligada, o convite de inscrição e o service worker (/asender-sw.js) já vêm no host da página; nada disso é preciso colar.

5. SDK @asender/pages-sdk

O repositório contém o SDK JavaScript @asender/pages-sdk (versão 0.2.1), com três pontos de entrada: . (servidor, com API key), ./client (navegador, sem credencial, com createBrowserClient e rastrearFormulario para o funil de um formulário seu) e ./chat (o widget de chat, o mesmo que chat.js entrega).

Ele ainda não está publicado no npm. Não há npm install @asender/pages-sdk funcionando hoje. Para o navegador, use os caminhos desta página, que não dependem de pacote:

A publicação do pacote está planejada. Quando sair, este guia passa a mostrar a instalação.

6. CSP e privacidade

Content-Security-Policy

Se o seu site usa CSP, libere o que for usar. Os domínios abaixo valem para o host canônico; acrescente os equivalentes .com.br se houver snippet antigo.

RecursoDiretivaO que liberar
Formulário incorporadoscript-srchttps://embed.asender.net e 'unsafe-inline' (veja a nota)
Formulário incorporadostyle-src'unsafe-inline'
Formulário incorporadoconnect-srchttps://embed.asender.net (envio, carimbo, eventos e endereço); https://sites.asender.net só para snippets antigos
Formulário incorporado, envio sem JavaScriptframe-src, form-actionhttps://embed.asender.net
Pixelscript-src, connect-srchttps://sites.asender.net
Chatscript-srchttps://sites.asender.net
Chatconnect-srchttps://api.atendimento.asender.net
Chatstyle-src'unsafe-inline' (o widget injeta seu estilo)
Web Pushconnect-srchttps://api.asender.net
Web Pushworker-src'self' (o service worker mora no seu domínio)

Exemplo para um site que usa tudo:

Content-Security-Policy:
  script-src  'self' 'unsafe-inline' https://embed.asender.net https://sites.asender.net;
  style-src   'self' 'unsafe-inline';
  connect-src 'self' https://embed.asender.net https://sites.asender.net
              https://api.atendimento.asender.net https://api.asender.net;
  frame-src   https://embed.asender.net;
  form-action 'self' https://embed.asender.net;
  worker-src  'self';
Por que 'unsafe-inline' no formulário. O formulário incorporado vem com <style> e vários <script> embutidos no próprio HTML (máscaras, anti-spam, funil). O embed.js recria esses scripts na sua página, e eles precisam de script-src 'unsafe-inline' (um nonce do seu site não é herdado por scripts criados dessa forma). Se a sua política não admite 'unsafe-inline', use o formulário só em uma página com política própria, ou abra o formulário publicado pelo Asender em vez de incorporá-lo. Pixel, chat e Web Push não exigem 'unsafe-inline' em script-src.

O que fica no navegador do visitante

PeçaOndeO quêQuanto dura
PixelsessionStorage _lz_sid aleatório da visitaaté a aba fechar
FormuláriolocalStorage asf_did aleatório do dispositivoaté o visitante apagar
FormuláriolocalStorage asf_v, asf_ftcontagem de visitas ao formulário e a origem da primeira visitaaté o visitante apagar
Formuláriocookies _fbp, _fbcsomente leitura, para a conversão de anúncionão escrevemos esses cookies
Chatcookie asender_chattoken da conversa, HttpOnly30 dias
Web Pushservice worker e assinatura de pushinscrição do navegadoraté o visitante cancelar

O pixel e o formulário não gravam cookie próprio.

Dados enviados junto do formulário

Além dos campos que a pessoa preencheu, o formulário envia um contexto técnico: página, idioma, fuso, tamanho de tela, tipo de dispositivo, parâmetros utm_* e identificadores de clique de anúncio presentes na URL (como gclid e fbclid), origem da primeira visita, número de visitas, id do dispositivo, tempo no formulário e a sessão do pixel, quando há. Não coleta impressão digital de canvas ou áudio, nem geolocalização do navegador. O IP e a geolocalização por IP são resolvidos no servidor. Os eventos do funil do formulário (/eventos) carregam só o nome dos campos tocados, nunca o valor.

Consentimento: o que é com você

O Asender não traz um banner de cookies. Você define a política do seu site. Pontos práticos: