Widget: identificar usuários logados

Quando o visitante já está autenticado no seu site, o widget pode abrir o atendimento sem pedir nome e telefone. Pessoa e empresa são criadas ou atualizadas no CRM no momento da identificação; a conversa só nasce quando a primeira mensagem é enviada.

1. Instale o widget

Copie o trecho de instalação em Configurações > Widget. No exemplo, substitua SEU-DOMINIO pelo endereço da sua plataforma e ID_DA_CONTA pelo identificador da conta.

<script src="https://SEU-DOMINIO/widget.js" data-account="ID_DA_CONTA" defer></script>

Os identificadores técnicos $hubzy, hubzySettings, os eventos hubzy:* e o nome de exemplo HUBZY_WIDGET_SECRET são mantidos por compatibilidade. Use-os como aparecem nos exemplos.

2. Informe quem está logado

// Depois do login, no seu app
await window.$hubzy.setUser("user_123", {
  name: "Maria Souza",
  email: "maria@empresa.com",
  phone: "+5511999999999", // opcional
  title: "Gerente de Operações",
  city: "São Paulo",
  company: {
    identifier: "org_42",
    name: "Empresa Exemplo",
    website: "https://empresa.com",
  },
  identityToken: "<token assinado no seu servidor>", // opcional, recomendado
});

// No logout
await window.$hubzy.reset();

O identifier é o identificador estável do usuário no seu sistema (nunca use e-mail que possa mudar). Identificadores diferentes nunca são mesclados automaticamente: cada um é um cadastro.

Alternativa declarativa

Quando o usuário já é conhecido no carregamento da página:

<script>
  window.hubzySettings = {
    user: { identifier: "user_123", name: "Maria Souza", email: "maria@empresa.com" },
  };
</script>
<script src="https://SEU-DOMINIO/widget.js" data-account="ID_DA_CONTA" defer></script>

3. Assine a identidade (recomendado)

Sem assinatura, a identidade vale apenas para o navegador atual — o histórico não é retomado em outro dispositivo, para evitar que alguém se passe por outro usuário. Com o token assinado, a conversa aberta é retomada em qualquer navegador e os dados do perfil são aceitos como verificados.

Gere o segredo em Configurações > Widget. Ele aparece uma única vez; guarde-o apenas no servidor. Rotacionar o segredo encerra as sessões verificadas em andamento.

// Node.js — no SEU servidor, nunca no navegador
import { createHmac } from "crypto";

const claims = {
  aud: ACCOUNT_ID,            // id da conta
  sub: "user_123",            // mesmo identificador passado ao setUser
  iat: Math.floor(Date.now() / 1000),
  exp: Math.floor(Date.now() / 1000) + 300, // no máximo 5 minutos
  profile: {
    name: "Maria Souza",
    email: "maria@empresa.com",
    company: { identifier: "org_42", name: "Empresa Exemplo" },
  },
};

const payload = Buffer.from(JSON.stringify(claims)).toString("base64url");
const signature = createHmac("sha256", HUBZY_WIDGET_SECRET).update(payload).digest("base64url");
const identityToken = payload + "." + signature;

Quando o token é usado, os dados de perfil considerados são os que estão dentro dele — o que vem do navegador é ignorado.

4. Eventos

window.addEventListener("hubzy:ready", () => {});
window.addEventListener("hubzy:user-set", (e) => console.log(e.detail.verified));
window.addEventListener("hubzy:reset", () => {});
window.addEventListener("hubzy:error", (e) => console.warn(e.detail.error));

// Mensagens novas com o chat minimizado
window.addEventListener("hubzy:unread", (e) => console.log(e.detail.count));
window.addEventListener("hubzy:notify", (e) => console.log(e.detail.preview));
console.log(window.$hubzy.unreadCount());

5. Botão próprio para abrir o chat

Para usar o seu próprio botão — em um app React, no seu painel ou dentro de um aplicativo desktop — instale o widget com data-hide-bubble="true". A bolinha padrão deixa de aparecer, mas o chat continua carregado, recebendo mensagens e contando as que ainda não foram vistas.

<!-- Esconde a bolinha padrão: quem abre o chat é o seu botão -->
<script src="https://SEU-DOMINIO/widget.js" data-account="ID_DA_CONTA" data-hide-bubble="true" defer></script>

<!-- Ou pela configuração declarativa -->
<script>
  window.hubzySettings = { hideMessageBubble: true };
</script>

Com a bolinha oculta, o cabeçalho do chat mostra um botão de fechar, e a tecla Esc dentro do chat também fecha o painel — assim o visitante nunca fica sem saída.

Controle o painel e reflita o estado no seu botão:

// Seu botão abre, fecha ou alterna o chat
botao.addEventListener("click", () => window.$hubzy.toggle());
window.$hubzy.toggle("open");   // abre
window.$hubzy.toggle("close");  // fecha

// Estado atual e mensagens não vistas, para desenhar o seu próprio selo
window.addEventListener("hubzy:toggle", (e) => setChatOpen(e.detail.open));
window.addEventListener("hubzy:unread", (e) => setNaoLidas(e.detail.count));
console.log(window.$hubzy.isOpen(), window.$hubzy.unreadCount());

// Em React, o padrão que você já usa também funciona
window.$hubzy.toggle(isChatOpen ? "close" : "open");
  • toggle("open") e toggle("close") definem o estado; sem argumento, alterna. open() e close() continuam válidos.
  • isOpen() devolve o estado atual e hubzy:toggle avisa cada mudança, inclusive quando o visitante fecha pelo botão de dentro do chat.
  • unreadCount() e hubzy:unread entregam a contagem de mensagens novas para você desenhar o seu próprio selo.
  • O chat só recebe mensagens enquanto a página estiver aberta: se o visitante fechar a aba, o aviso aparece novamente na próxima visita.

Erros possíveis

  • identity_invalid — token expirado, assinatura errada, ou aud/sub diferentes da conta e do identificador.
  • identity_conflict — não foi possível vincular a identidade ao cadastro. Caso raro: telefone repetido não bloqueia mais a identificação.
  • rate_limited — muitas identificações sem assinatura em pouco tempo.
  • invalid_account — conta inexistente ou inativa.
  • invalid_payload — faltou a conta ou o identificador. A resposta traz fields com os nomes dos campos recusados (sem os valores).

Campos do perfil

  • Obrigatórios: apenas o identificador do usuário (e o da empresa, quando enviar empresa).
  • Um campo que não passa nas regras (por exemplo e-mail em formato inválido ou telefone sem DDD) é ignorado e não impede o atendimento; ele volta em ignored_fields.
  • Campo ausente permanece como está; campo enviado em branco ou null limpa o valor. Empresa sem identificador ou nome é descartada.

Boas práticas

  • Chame reset() no logout: a sessão do navegador é revogada.
  • Gere o token no servidor a cada carregamento de página, com validade curta.
  • Nunca exponha o segredo em código do navegador nem em repositórios.
  • Telefone é opcional para usuários identificados; o identificador externo é a chave.
  • Dois identificadores diferentes que informem o mesmo telefone passam a apontar para o mesmo cadastro de pessoa no CRM, cada um com a sua própria conversa. Se o telefone já pertencer a outra pessoa, ele não é sobrescrito — a duplicidade fica para revisão no CRM.
  • Se a identificação falhar, o chat não trava: ele volta ao formulário de visitante com os dados já informados, para que a conversa possa começar de qualquer forma.