Pular para o conteúdo principal

Widget de chat web Copera Omni: configuração, SDK e identidade

O widget web Copera Omni adiciona chat ao seu site e encaminha cada conversa para um canal Omni — uma caixa de entrada compartilhada que pode receber conversas de várias fontes ao mesmo tempo, como um ou mais widgets web e números do WhatsApp, para que sua equipe trabalhe com todas elas em um só lugar.

Este guia leva você de uma instalação de dois minutos a uma integração pronta para produção: a incorporação copiar e colar, a API de comandos CoperaOmni para iniciadores personalizados, a segurança por origem do navegador e o fluxo seguro para identificar visitantes autenticados sem nunca expor uma chave do servidor no navegador.

Fontes gratuitas vs. pagas

Um canal Omni pode combinar várias fontes. O widget web é o gratuito; o WhatsApp é um complemento pago.

Widget web — Grátis

Adicione quantas fontes de widget web precisar, sem custo. Tudo neste guia usa o widget web gratuito.

WhatsApp — Complemento pago

Conecte números do WhatsApp ao mesmo canal Omni como complementos pagos, para que conversas da web e do WhatsApp cheguem em uma única caixa de entrada.

Remover uma fonte não cancela um número comprado

Remover uma fonte do WhatsApp ou excluir um canal Omni não cancela a vaga de número comprada. Para parar de pagar por uma vaga, reduza a quantidade comprada separadamente em Faturamento do workspace.

Início rápido

Dois minutos até um widget no ar.

Adicione uma fonte de widget web

Na Copera, abra (ou crie) um canal Omni, vá em Configurações → Adicionar fonte e escolha Widget web — a Copera identifica essa fonte como Grátis. Depois, copie a channelKey exibida em Configurar e instalar.

Instale o snippet antes de </body>

Escolha Quick embed ou JavaScript SDK abaixo, cole em sua página e substitua YOUR_CHANNEL_KEY pela chave que você copiou.

Recarregue sua página

O iniciador flutuante da Copera aparece na posição que você configurou. Abra-o para iniciar uma conversa.

Coloque este snippet completo uma única vez, logo antes da tag de fechamento </body>. Ele carrega o runtime da CDN de forma assíncrona, inicializa a fonte e exibe o iniciador flutuante da Copera.

index.html
<script>
(function (w, d) {
w.CoperaOmni = w.CoperaOmni || function () {
(w.CoperaOmni.q = w.CoperaOmni.q || []).push(arguments);
};
var s = d.createElement('script');
s.async = 1;
s.src = 'https://widget.copera.ai/widget.js';
d.head.appendChild(s);
})(window, document);
CoperaOmni('init', { channelKey: 'YOUR_CHANNEL_KEY' });
</script>

Isso é tudo o que um site HTML simples precisa. Para controlar o painel a partir do seu próprio botão em vez do iniciador flutuante, mude para a aba JavaScript SDK.

Chave pública, não ID do canal

A channelKey gerada é a chave pública dessa fonte de widget web específica. É seguro incluí-la no código do navegador. Ela não é o ID do canal Omni nem o ID da fonte, e não deve ser substituída por nenhum deles.

Gerar a chave novamente quebra incorporações existentes

Ao selecionar Gerar chave novamente, a channelKey antiga deixa de funcionar. Substitua-a em todos os locais onde o widget está incorporado.

Configurar o widget

O início rápido usa os padrões. Abra as Configurações da fonte do widget (ou Configurar e instalar) para personalizar toda a experiência antes de ir para produção.

Crie ou abra um canal Omni

Crie um canal do tipo Omni ou abra um existente. Um único canal Omni pode receber conversas de várias fontes.

Adicione a fonte de widget web

Abra as Configurações do canal, selecione Adicionar fonte e escolha Widget web. A Copera identifica essa fonte como Grátis.

Configure a experiência

Informe um Nome de exibição, escolha a Cor principal e a Posição do iniciador e, se quiser, defina uma Mensagem de saudação. Também é possível ativar Exibir formulário pré-chat para visitantes anônimos.

Proteja a incorporação

Em uma nova integração, escolha Origem do navegador (recomendado) em Segurança da incorporação. Adicione a Origens permitidas cada origem exata do site que poderá incorporar o widget, pressionando Enter após cada uma — por exemplo, https://www.example.com e https://app.example.com.

Escolha o comportamento de identidade

Deixe Exigir identidade verificada do visitante desativado para permitir conversas anônimas ou com pré-chat. Ative quando seu site sempre chamar identify com um token de identidade emitido pelo servidor. O formulário pré-chat e a identidade verificada obrigatória não podem ser ativados juntos.

Crie e instale

Selecione Criar widget. Na tela de sucesso, copie a Quick embed para o iniciador integrado ou selecione JavaScript SDK para um iniciador personalizado. Depois, você pode voltar à fonte e selecionar Configurar e instalar.

ConfiguraçãoO que controlaPadrão
Nome de exibiçãoO nome exibido no topo do painel de chat.Nome da fonte
Cor principalA cor de destaque do iniciador e do painel.Cor de destaque do workspace
Posição do iniciadorEm qual canto o iniciador flutuante fica.Inferior direito
Mensagem de saudaçãoUma primeira mensagem opcional exibida quando o painel abre.Nenhuma
Exibir formulário pré-chatPede dados a visitantes anônimos antes de a conversa começar.Desativado
Segurança da incorporaçãoComo a Copera decide quais páginas podem incorporar o widget.Origem do navegador
Exigir identidade verificada do visitanteBloqueia conversas anônimas e com pré-chat; exige um token de identidade emitido pelo servidor.Desativado

API de comandos JavaScript

https://widget.copera.ai/widget.js instala a função global de comandos CoperaOmni(command, ...args). Chamadas feitas pelo snippet de fila antes de o runtime terminar de carregar são armazenadas e reproduzidas em ordem.

Comandos

ComandoAssinaturaFinalidade
initCoperaOmni('init', config)Inicializa o widget. config.channelKey é obrigatória; locale e launcher são opcionais.
identifyCoperaOmni('identify', identity)Define a identidade do visitante. Prefira { identityToken } para usuários autenticados; { name, email } aceita dados não verificados do visitante.
logoutCoperaOmni('logout')Limpa a identidade atual antes de um usuário sair ou de outro usuário assumir a página.
destroyCoperaOmni('destroy')Remove o iframe, o iniciador, os temporizadores, os listeners e as credenciais em memória.
openCoperaOmni('open')Abre o painel do chat.
closeCoperaOmni('close')Fecha o painel do chat.
toggleCoperaOmni('toggle')Alterna o painel entre aberto e fechado.
setLauncherVisibleCoperaOmni('setLauncherVisible', visible)Exibe ou oculta o iniciador integrado sem destruir o widget.
updateCoperaOmni('update', { locale })Altera o idioma do widget ativo.
onCoperaOmni('on', eventName, callback)Assina um evento. O runtime ativo retorna uma função de cancelamento.
offCoperaOmni('off', eventName, callback)Remove o mesmo callback passado anteriormente a on.

As opções aceitas por init são:

OpçãoTipoPadrãoDescrição
channelKeystringObrigatóriaChave pública da fonte copiada de Configurar e instalar.
localestring"en"Locale BCP 47 da interface do widget, como "en" ou "pt-BR".
launcher"default" | "custom""default"Use "custom" para ocultar o iniciador da Copera e controlar o painel você mesmo.

Eventos

Cada callback de evento recebe um objeto cujo name identifica o evento.

EventoPayloadQuando é disparado
ready{ name: 'ready' }O iframe está pronto e enviou seu estado inicial. Isso não comprova que a inicialização do backend funcionou.
open{ name: 'open' }O painel é aberto.
close{ name: 'close' }O painel é fechado.
identityRequired{ name: 'identityRequired' }Uma conversa encerrada está sendo reiniciada em uma fonte que exige uma nova verificação do visitante.
unreadCount{ name: 'unreadCount', count: number }A quantidade de mensagens não lidas muda.
conversationStarted{ name: 'conversationStarted', conversationId: string }Uma conversa começa e seu ID fica disponível.

Atualize um indicador personalizado e registre o início de uma conversa:

support-widget.js
const unreadBadge = document.querySelector('#support-unread');

function handleUnread(event) {
unreadBadge.textContent = String(event.count);
unreadBadge.hidden = event.count === 0;
}

function handleConversationStarted(event) {
console.log('Conversa Omni iniciada', event.conversationId);
}

CoperaOmni('on', 'unreadCount', handleUnread);
CoperaOmni('on', 'conversationStarted', handleConversationStarted);

// Quando este componente da página for removido:
CoperaOmni('off', 'unreadCount', handleUnread);
CoperaOmni('off', 'conversationStarted', handleConversationStarted);

Mantenha a referência do callback se pretende chamar off; uma nova função inline não é o mesmo listener.

Use eventos de ciclo de vida para manter a interface host sincronizada:

support-widget.js
CoperaOmni('on', 'ready', function () {
document.querySelector('#support-chat').disabled = false;
});

CoperaOmni('on', 'open', function () {
document.querySelector('#support-chat').setAttribute('aria-expanded', 'true');
});

CoperaOmni('on', 'close', function () {
document.querySelector('#support-chat').setAttribute('aria-expanded', 'false');
});

CoperaOmni('on', 'identityRequired', function () {
// Solicite ao aplicativo host autenticado que renove o token de identidade.
void identifyCurrentUser();
});

Identidade do visitante

Escolha o quanto você sabe sobre cada visitante. Visitantes anônimos e com pré-chat não precisam de backend; visitantes verificados usam um token de curta duração emitido pelo servidor.

Deixe Exigir identidade verificada do visitante desativado. Um visitante pode começar sem dados de identidade. A Copera mantém a sessão do widget do navegador associada à conversa.

Chamar identify com { name, email } fornece dados não verificados do visitante. Para a identidade de uma conta autenticada, use { identityToken } — descrito a seguir.

Identidade verificada segura

A identidade verificada tem três limites:

  1. A Copera emite uma chave de API do servidor vinculada à fonte com o prefixo cp_omni_sk_.
  2. Seu backend envia à Copera um identificador estável do cliente e recebe um token de identidade válido por cinco minutos.
  3. Seu navegador recebe somente o token de curta duração e o passa ao widget.
Nunca exponha a chave de API do servidor

A chave cp_omni_sk_… deve ficar apenas no armazenamento de segredos do seu backend. Nunca a coloque em HTML, JavaScript do navegador, um aplicativo móvel, logs, propriedades de analytics ou um repositório público. A channelKey pública e a chave de API do servidor privada têm finalidades diferentes e não são intercambiáveis.

Crie uma chave do servidor vinculada à fonte

Abra o painel Configurar e instalar da fonte do widget. Em Chaves de API do servidor, selecione Criar chave do servidor, dê a ela o nome de um backend ou ambiente e copie-a imediatamente — ela é exibida uma única vez. Há suporte a várias chaves ativas, o que permite a rotação sem compartilhar uma credencial entre ambientes.

Armazene-a como uma variável de ambiente exclusiva do backend, por exemplo COPERA_OMNI_SERVER_KEY.

Emita um token pelo seu backend

Seu backend chama o endpoint de tokens de identidade com a chave do servidor:

Requisição
POST https://api.copera.ai/public/v1/omni-channel/identity-tokens
Authorization: Bearer cp_omni_sk_...
Content-Type: application/json

O corpo da requisição aceita:

CampoObrigatórioDescrição
externalIdSimUm identificador opaco, estável e sem PII para o cliente autenticado, limitado ao seu aplicativo. Use o mesmo valor em visitas futuras.
nameNãoNome de exibição atual, vindo do seu cadastro de conta confiável.
emailNãoE-mail atual, vindo do seu cadastro de conta confiável.

A chave do servidor já vincula a requisição a um workspace e a uma fonte de widget web; não envie ID do workspace, ID da fonte, ID do canal nem channelKey nesta requisição. Consulte a referência da API para criar um token de identidade do Omni para ver o schema exato e as respostas.

A rota Node.js abaixo ilustra o padrão de mesma origem. Ela pressupõe que seu aplicativo já autenticou a requisição e disponibilizou o usuário autenticado como request.user.

server/routes/omni-identity.js
export async function postOmniIdentity(request, response) {
const user = request.user;
if (!user) {
return response.status(401).json({ message: 'É necessário entrar' });
}

const coperaResponse = await fetch(
'https://api.copera.ai/public/v1/omni-channel/identity-tokens',
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.COPERA_OMNI_SERVER_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
externalId: user.omniExternalId,
name: user.name,
email: user.email,
}),
},
);

if (!coperaResponse.ok) {
return response.status(502).json({ message: 'Não foi possível iniciar o chat de suporte' });
}

const { identityToken, expiresAt } = await coperaResponse.json();
response.setHeader('Cache-Control', 'no-store');
return response.json({ identityToken, expiresAt });
}

Para o mesmo externalId estável dentro dessa fonte de widget, a Copera cria o contato na primeira vez e reutiliza esse mesmo contato em sessões verificadas futuras. Use um valor opaco criado para o seu aplicativo. Não use um nome de exibição, e-mail, telefone, nome de usuário, ID sequencial de banco de dados nem outro valor diretamente identificável ou mutável.

Busque no navegador e identifique

Exponha a rota na mesma origem do seu aplicativo, exija a sessão autenticada normal e as proteções CSRF do aplicativo e retorne somente o token de curta duração:

app/support-chat.js
async function identifyCurrentUser() {
const response = await fetch('/api/omni-identity', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': window.appCsrfToken,
},
});

if (!response.ok) {
throw new Error(`Falha na requisição de identidade Omni: ${response.status}`);
}

const { identityToken } = await response.json();
await CoperaOmni('identify', { identityToken });
}

CoperaOmni('init', { channelKey: 'YOUR_CHANNEL_KEY' });
void identifyCurrentUser().catch(function (error) {
console.error('Não foi possível identificar o visitante Omni', error);
});

Os tokens de identidade expiram cinco minutos após serem emitidos. Emita-os sob demanda e use-os imediatamente; não os persista no armazenamento local nem os trate como um token de login duradouro.

Troca de usuários na mesma página

Chame e aguarde CoperaOmni('logout') antes de identificar um usuário autenticado diferente na mesma página do navegador. Ao sair do aplicativo, chame logout mesmo que pretenda manter o chat anônimo disponível. Isso impede que a identidade de um cliente passe para a sessão de outro cliente.

app/support-chat.js
async function switchOmniUser(nextUserIsSignedIn) {
await CoperaOmni('logout');

if (nextUserIsSignedIn) {
await identifyCurrentUser();
}
}

Quando um visitante reinicia uma conversa encerrada e Exigir identidade verificada do visitante está ativado, o widget emite identityRequired para que o site verifique o visitante novamente. Solicite um token novo e chame identify; não recorra a name e email fornecidos pelo navegador como se fossem verificados. Na primeira visita autenticada, identifique o visitante de forma proativa após init, como mostrado acima.

Segurança por origem do navegador

Origem do navegador (recomendado) compara a página host que incorpora o widget com as Origens permitidas da fonte e estabelece uma sessão de incorporação de curta duração vinculada à origem. Adicione a origem da página que hospeda o widget, como https://support.example.comnão https://widget.copera.ai. Configure origens exatas, incluindo o esquema e a porta quando houver:

URL da páginaOrigem permitida
https://www.example.com/pricinghttps://www.example.com
https://app.example.com/supporthttps://app.example.com
http://localhost:3000/accounthttp://localhost:3000

Caminhos, consultas, fragmentos, nomes de usuário e senhas não fazem parte de uma origem. Adicione cada subdomínio separadamente. Prefira HTTPS fora do desenvolvimento local.

Escolha Origem do navegador (recomendado) para novas implantações e configure explicitamente cada origem permitida. Ao adicionar ou remover um domínio de produção, atualize Origens permitidas antes de implantar a incorporação nele. Remover uma origem impede novas sessões de incorporação a partir dela.

Rotação e revogação

Trate a chave pública de incorporação e as chaves de API do servidor como credenciais separadas:

AçãoEfeito imediatoAcompanhamento
Gerar chave novamenteSnippets existentes que usam a channelKey antiga deixam de funcionar.Substitua a chave em todas as incorporações.
Revogar uma chave de API do servidorRequisições de emissão de token que usam essa chave cp_omni_sk_… falham imediatamente.Implante uma chave substituta antes, caso a integração precise continuar disponível.

Para uma rotação da chave do servidor sem indisponibilidade, crie uma segunda chave, implante-a no backend, confirme que o valor de Último uso foi atualizado e então revogue a chave antiga. Use chaves distintas para produção, homologação e cada backend independente.

Locale e ciclo de vida

Defina o locale inicial em init e use update se o visitante mudar de idioma:

app/support-chat.js
CoperaOmni('init', {
channelKey: 'YOUR_CHANNEL_KEY',
locale: 'en',
});

function onApplicationLocaleChanged(locale) {
CoperaOmni('update', { locale });
}

Para um aplicativo de página única:

  • Chame init uma vez para a integração montada do widget.
  • Assine com on e remova listeners com off quando o componente proprietário for desmontado.
  • Chame logout quando o usuário do aplicativo sair ou mudar.
  • Chame destroy quando a própria integração do widget for removida permanentemente ou quando você precisar intencionalmente de uma instância nova.

Solução de problemas

O script do widget não carrega

Proteja o carregamento do script. O snippet direto da CDN consegue detectar uma falha de rede ou de CSP pelo evento error do elemento de script:

index.html
<script>
(function (w, d) {
w.CoperaOmni = w.CoperaOmni || function () {
(w.CoperaOmni.q = w.CoperaOmni.q || []).push(arguments);
};
var s = d.createElement('script');
s.async = 1;
s.src = 'https://widget.copera.ai/widget.js';
s.onerror = function () {
console.error('Não foi possível carregar o widget Copera Omni.');
};
d.head.appendChild(s);
})(window, document);
CoperaOmni('init', { channelKey: 'YOUR_CHANNEL_KEY' });
</script>

Se a requisição for bloqueada, verifique sua Content Security Policy e confirme que a origem da página host está em Origens permitidas.

Como confirmar que a inicialização foi bem-sucedida?

init, identify, logout e destroy podem retornar promises após a instalação do runtime ativo. Aguarde as transições de identidade e sessão e trate as rejeições. Ao chamar o dispatcher ativo diretamente ou usar o wrapper tipado, aguarde init() para confirmar a inicialização do backend.

Comandos enfileirados antes de o runtime instalar são disparados sem espera de retorno; o evento ready só confirma que o iframe está pronto e que seu estado inicial foi enviado — ele não comprova que a inicialização do backend foi bem-sucedida.

As requisições de token de identidade falham
  • Retorne um erro genérico do seu backend; nunca encaminhe a chave do servidor nem o corpo da resposta do provedor ao navegador.
  • Repita apenas falhas transitórias do servidor, com recuo limitado.
  • Emita um token novo após a expiração em vez de reutilizar um token antigo.
  • Trate 401 do endpoint de tokens como uma chave do servidor ausente, malformada ou revogada, e faça a rotação ou substituição.
  • Trate 403 como uma fonte de widget indisponível e verifique se ela está conectada e não suspensa.

Content Security Policy

Permita as origens Copera para uma CSP estrita

Se o seu site usa Content Security Policy (CSP), permita as origens Copera mínimas necessárias nas diretivas relevantes:

  • script-src: https://widget.copera.ai para o widget.js.
  • frame-src: https://widget.copera.ai para o iframe do painel de chat.
  • connect-src: https://api.copera.ai para as requisições feitas pela página host.
  • style-src: o runtime atual do widget cria elementos e atributos de estilo e não oferece uma alternativa com nonce ou hash. Portanto, a integração com CSP estrita exige 'unsafe-inline' somente em style-src — nunca adicione essa opção a script-src.
  • Sua política também deve permitir o bootstrap inline mostrado em Quick embed. Se a sua política bloqueia scripts inline, mova o bootstrap para um arquivo externo permitido ou autorize-o com a política de nonce ou hash do seu site. Não enfraqueça a política com 'unsafe-inline' em script-src.
  • Configure em Origens permitidas a origem da página host que incorpora o widget, por exemplo https://support.example.com — não https://widget.copera.ai. A permissão de CSP não substitui a verificação de origem da Copera.

Após alterar a CSP, teste com a política em modo de bloqueio: verifique o iniciador, a abertura do painel, o início de uma conversa, o recebimento de uma atualização de não lidas e a identidade verificada no console do navegador, sem nenhuma requisição bloqueada.

Runtime da CDN e wrapper tipado

O runtime da CDN em https://widget.copera.ai/widget.js é o próprio widget e é tudo o que uma integração HTML simples precisa. @copera/omni-widget-sdk é um wrapper tipado opcional para aplicativos TypeScript: ele injeta o mesmo runtime da CDN uma vez, armazena chamadas antecipadas e expõe uma fachada tipada para os mesmos comandos e eventos. Ele não substitui o widget da CDN nem altera o fluxo de identidade do servidor.

Use os exemplos diretos do runtime deste guia, a menos que seu aplicativo já consuma o wrapper tipado. As instruções de instalação do pacote e as alternativas de CDN do pacote estão intencionalmente fora deste guia de incorporação.

Perguntas frequentes

O widget web Copera Omni é gratuito?

O widget web é gratuito. Números do WhatsApp conectados a um canal Omni são complementos pagos, e remover uma fonte do WhatsApp ou excluir seu canal não cancela a vaga de número comprada. Reduza a quantidade comprada separadamente em Faturamento do workspace.

É seguro usar a channelKey do widget no código do navegador?

Sim. A channelKey é a chave pública de uma fonte de widget web e pertence ao código de incorporação. Ela não é um ID de canal, ID de fonte nem a chave de API do servidor privada cp_omni_sk_…. Gerar a channelKey novamente interrompe imediatamente as incorporações que ainda usam o valor antigo.

Como identificar um visitante autenticado com segurança?

Autentique o visitante no backend do seu aplicativo, troque a chave cp_omni_sk_… vinculada à fonte por um token de identidade válido por cinco minutos e retorne ao navegador somente esse token de curta duração. Depois, chame CoperaOmni('identify', { identityToken }). Nunca exponha a chave de API do servidor ao navegador ou a um cliente móvel.

Como restringir quais sites podem incorporar o widget?

Escolha Origem do navegador (recomendado) e adicione a Origens permitidas cada origem exata permitida, incluindo o esquema e a porta quando houver. Adicione subdomínios separadamente. As permissões de Content Security Policy não substituem a verificação de origens permitidas da Copera.

Documentação relacionada