Controle o widget a partir da sua página e mantenha cada conversa resiliente — reconexão automática, reenvio de mensagens, detecção de offline, timeouts e tratamento de erros amigável.
Uma vez que o script do widget é carregado, o Companin registra uma ponte de host em window.CompaninWidgetHost. Ele dá à sua página uma pequena API sem dependências para abrir e fechar o widget, enviar mensagens, ler estado e assinar eventos de ciclo de vida — sem acoplar seu código aos internos do widget.
A ponte também adiciona uma camada de confiabilidade sobre o widget: mensagens são enfileiradas enquanto offline, reencaminhadas automaticamente quando a conexão retorna, expiram se nenhuma resposta chega e o widget se reconecta automaticamente após erros transitórios. Cada mudança de estado é exposta como um evento DOM para que você possa reagir em sua própria interface.
Chame esses métodos em window.CompaninWidgetHost após o widget ter sido carregado. Eles são seguros e não fazem nada quando o widget ainda não está pronto, então você nunca precisa proteger cada chamada.
open() / close() / toggle() — Mostrar, ocultar ou inverter o painel do widget.sendText(text) — Enviar uma mensagem de texto simples como visitante.sendPayload(payload) — Enviar uma mensagem estruturada ou objeto de comando.sendSafe(payload) — Enviar através da camada de confiabilidade — enfileirado quando offline e passado por qualquer interceptores.sendWithTimeout(payload, ms) — Enviar e emitir um evento de timeout se nenhuma resposta chegar dentro de ms (padrão 10000).intercept(fn) — Registrar uma função que pode reescrever ou cancelar mensagens de saída; retorna uma função de cancelamento de inscrição.getState() — Ler o estado atual do host: status aberto, última mensagem enviada e recebida, sinalizador online e histórico de comandos.getIsOnline() — Se o host atualmente considera a conexão online.drainRetryQueue() — Limpar manualmente quaisquer mensagens enfileiradas enquanto offline.cleanup() — Cancelar a inscrição de todos os ouvintes — chame antes de remover o widget.<script> window.addEventListener('load', function () { var host = window.CompaninWidgetHost; if (!host) return; host.open(); host.sendText('Hi! I have a question about pricing.'); console.log(host.getState()); });</script>Deixe o widget reconhecer seus usuários logados para que as conversas sejam personalizadas e restauradas em seus dispositivos. Seu servidor assina um token de curta duração que o widget entrega ao Companin; o Companin o verifica e vincula a sessão a esse usuário.
1. Obtenha seu segredo de assinatura. No painel, abra Instalar → Usuários logados → Gerar segredo, depois copie-o para o ambiente do seu servidor. Nunca o exponha no código do navegador.
2. Assine um token em seu servidor — um JWT HS256 de curta duração contendo o id do usuário (sub), email e nome:
const jwt = require('jsonwebtoken'); // npm i jsonwebtokenfunction signUserToken(user) { return jwt.sign( { sub: String(user.id), email: user.email, name: user.name }, process.env.COMPANIN_EMBED_SECRET, { algorithm: 'HS256', expiresIn: '5m' } );}3. Entregue o token ao widget. Em uma página renderizada pelo servidor, adicione-o à tag de script como data-user-token; em um aplicativo de página única, chame identify() após o usuário fazer login:
<!-- Option A: server-rendered page — put the signed token on the script tag --><script src="https://YOUR_WIDGET_HOST/widget.js" data-widget-key="wgt_your_key" data-user-token="SERVER_SIGNED_JWT"></script><!-- Option B: after login — fetch a fresh token and call identify() --><script> fetch('/api/widget-user-token') .then(function (r) { return r.json(); }) .then(function (data) { if (data.token) window.CompaninWidget.identify({ token: data.token }); });</script>Um token ruim ou expirado é ignorado — o widget simplesmente permanece anônimo, então é seguro sempre tentar a identificação.
Use sendSafe em vez de sendText quando a entrega importa. O host observa os eventos online e offline do navegador; enquanto offline, as mensagens são adicionadas a uma fila de reenvio e um evento companin:widget:offline é disparado. Assim que a conexão retorna, a fila é drenada automaticamente em ordem e um evento companin:widget:online é disparado.
window.CompaninWidgetHost.sendSafe('Track my order #1234');window.addEventListener('companin:widget:offline', function () { showBanner('You are offline — your message will send automatically.');});window.addEventListener('companin:widget:online', function () { showBanner('Back online.');});window.addEventListener('companin:widget:retryDrained', function (e) { showBanner(e.detail.count + ' queued message(s) sent.');});Envolva um envio em sendWithTimeout para se proteger contra uma resposta que nunca chega. Se nenhuma resposta for recebida dentro do timeout (10 segundos por padrão), um evento companin:widget:timeout é disparado para que você possa mostrar um prompt de reenvio amigável em vez de deixar o usuário esperando.
window.CompaninWidgetHost.sendWithTimeout('Are you there?', 8000);window.addEventListener('companin:widget:timeout', function () { showRetryPrompt('That took longer than expected. Try again?');});Quando o widget relata um erro, o host tenta reconectar até três vezes com um aumento progressivo (1,5s, 3s, depois 4,5s), emitindo companin:widget:reconnecting em cada tentativa. Uma resposta bem-sucedida redefine o contador; se todas as tentativas falharem, companin:widget:reconnectFailed é disparado para que você possa voltar de forma elegante.
window.addEventListener('companin:widget:reconnecting', function (e) { console.log('Reconnecting — attempt', e.detail.attempt, 'in', e.detail.delay, 'ms');});window.addEventListener('companin:widget:reconnectFailed', function () { showBanner('We could not reconnect. Please refresh the page.');});Registre um interceptor com intercept(fn) para inspecionar, reescrever ou cancelar cada mensagem de saída. Retorne um payload modificado para alterá-lo, retorne false para cancelar o envio ou retorne nada para deixá-lo passar inalterado. intercept retorna uma função de cancelamento de inscrição.
const stop = window.CompaninWidgetHost.intercept(function (payload) { if (typeof payload === 'string') { if (!payload.trim()) return false; // cancel the send return payload.replace(/[\w.+-]+@[\w-]+\.[\w.-]+/g, '[email]'); } return payload;});// Later, to remove the interceptor:stop();O host re-emite cada mudança de ciclo de vida do widget como um DOM CustomEvent em window, para que você possa reagir sem manter uma referência ao widget. Os dados relevantes estão em event.detail.
companin:widget:open / close — O painel do widget foi aberto ou fechado.companin:widget:message / response — O visitante enviou uma mensagem ou o agente respondeu.companin:widget:authFailure — A autenticação com o backend falhou.companin:widget:error — O widget relatou um erro.companin:widget:offline / online — O navegador perdeu ou recuperou sua conexão.companin:widget:queued / retryDrained — Uma mensagem foi enfileirada enquanto offline, ou a fila foi esvaziada.companin:widget:reconnecting / reconnectFailed — Uma tentativa de reconexão automática começou, ou todas as tentativas foram esgotadas.companin:widget:timeout — Uma mensagem não recebeu uma resposta dentro do seu timeout.window.addEventListener('companin:widget:message', function (e) { console.log('Visitor sent:', e.detail.message);});window.addEventListener('companin:widget:response', function (e) { console.log('Agent replied:', e.detail.response);});window.addEventListener('companin:widget:authFailure', function (e) { console.warn('Widget auth failed:', e.detail.error);});Código desacoplado pode acionar o widget disparando um evento companin:widget:command em vez de chamar a API diretamente. Envie uma string para entregar uma mensagem, ou um objeto de detalhe como { action: 'open' } ou { text: 'Olá' }. Isso é útil para tags de análise, GTM ou outros scripts que não devem importar o widget.
// Open the widget from anywhere — no widget reference needed.window.dispatchEvent(new CustomEvent('companin:widget:command', { detail: { action: 'open' }}));// Or send a message.window.dispatchEvent(new CustomEvent('companin:widget:command', { detail: { text: 'I need help with billing' }}));Defina window.__COMPANIN_WIDGET_WEBHOOK_URL para um endpoint coletor e o host encaminha eventos de abertura, fechamento, mensagem e resposta para ele como JSON via navigator.sendBeacon (recaindo para um fetch de keepalive). Isso é um complemento leve, do lado do cliente, para webhooks do lado do servidor — útil para análises de primeira parte.
// Point the host at your collector before the widget loads.window.__COMPANIN_WIDGET_WEBHOOK_URL = 'https://example.com/collect/widget';