Vai al contenuto principale

Widget web chat Copera Omni: setup, SDK e identità

Il widget web Copera Omni aggiunge la web chat al tuo sito e instrada ogni conversazione in un channel Omni — una inbox condivisa che può ricevere conversazioni da più source contemporaneamente, come uno o più web widget e numeri WhatsApp, così il team lavora su tutte in un unico posto.

Questa guida ti porta da un'installazione di due minuti a un'integrazione production-grade: l'embed copy-paste, la command API CoperaOmni per launcher custom, la sicurezza browser-origin e il flusso sicuro per identificare i visitatori autenticati senza mai esporre una server key nel browser.

Source gratuite vs a pagamento

Un channel Omni può combinare diverse source. Il web widget è quella gratuita; WhatsApp è un add-on a pagamento.

Web widget — Gratuito

Aggiungi tutte le source web-widget di cui hai bisogno senza costi. Tutto in questa guida usa il web widget gratuito.

WhatsApp — Add-on a pagamento

Collega numeri WhatsApp allo stesso channel Omni come add-on a pagamento, così le conversazioni web e WhatsApp finiscono in un'unica inbox.

Rimuovere una source non annulla un numero acquistato

Rimuovere una source WhatsApp o eliminare un channel Omni non annulla lo slot del numero acquistato. Per smettere di pagare uno slot, riduci la quantità acquistata separatamente in Workspace Billing.

Quick start

Due minuti per un widget live.

Aggiungi una source Web widget

In Copera, apri (o crea) un channel Omni, vai su Settings → Add source e scegli Web widget — Copera etichetta questa source come Free. Poi copia il channelKey mostrato sotto Configure & install.

Installa lo snippet prima di </body>

Scegli Quick embed o JavaScript SDK sotto, incollalo nella pagina e sostituisci YOUR_CHANNEL_KEY con la key che hai copiato.

Ricarica la pagina

Il floating launcher di Copera compare nella posizione che hai configurato. Aprilo per avviare una conversazione.

Posiziona questo snippet completo una sola volta, subito prima del tag di chiusura </body>. Carica il runtime CDN in modo asincrono, inizializza la source e mostra il floating launcher di 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>

Questo è tutto ciò di cui un sito HTML semplice ha bisogno. Per controllare il panel dal tuo bottone invece del floating launcher, passa alla tab JavaScript SDK.

Chiave pubblica, non un channel ID

Il channelKey generato è la chiave pubblica di questa source web-widget specifica. È sicuro metterlo nel codice browser. Non è l'Omni channel ID o source ID, e non deve essere sostituito con nessuno dei due.

Rigenerare la key interrompe gli embed esistenti

Se selezioni Regenerate key, il vecchio channelKey smette di funzionare. Sostituiscilo ovunque il widget sia incorporato.

Configurare il widget

Il quick start usa i default. Apri Settings (o Configure & install) della source widget per personalizzare l'esperienza completa prima di andare live.

Crea o apri un channel Omni

Crea un channel usando il tipo Omni, oppure aprine uno esistente. Un singolo channel Omni può ricevere conversazioni da più source.

Aggiungi la source web widget

Apri le Settings del channel, seleziona Add source, poi scegli Web widget. Copera etichetta questa source come Free.

Configura l'esperienza

Inserisci un Display name, scegli Primary color e Launcher position, e opzionalmente imposta un Greeting message. Puoi anche abilitare Show a pre-chat form per i visitatori anonimi.

Proteggi l'embed

Per una nuova integrazione, scegli Browser origin (recommended) sotto Embed security. Aggiungi ogni origin esatta del sito che può incorporare il widget ad Allowed origins, premendo Enter dopo ciascuna — ad esempio, https://www.example.com e https://app.example.com.

Scegli il comportamento dell'identità

Lascia Require verified visitor identity spento per consentire conversazioni anonime o pre-chat. Attivalo quando il sito chiamerà sempre identify con un identity token emesso dal server. Il pre-chat form e l'identità verificata obbligatoria non possono essere abilitati insieme.

Crea e installa

Seleziona Create widget. Nella schermata di successo, copia Quick embed per il launcher integrato oppure seleziona JavaScript SDK per un launcher custom. Puoi tornare alla source e selezionare Configure & install in seguito.

SettingWhat it controlsDefault
Display nameThe name shown at the top of the chat panel.Source name
Primary colorThe accent color of the launcher and panel.Workspace accent
Launcher positionWhich corner the floating launcher sits in.Bottom-right
Greeting messageAn optional first message shown when the panel opens.None
Show a pre-chat formAsks anonymous visitors for details before the conversation begins.Off
Embed securityHow Copera decides which pages may embed the widget.Browser origin
Require verified visitor identityBlocks anonymous and pre-chat chats; requires a server-issued identity token.Off

JavaScript command API

https://widget.copera.ai/widget.js installa la funzione di comando globale CoperaOmni(command, ...args). Le chiamate fatte tramite lo snippet di coda prima che il runtime finisca di caricarsi vengono bufferizzate e riprodotti in ordine.

Comandi

CommandSignaturePurpose
initCoperaOmni('init', config)Initialize the widget. config.channelKey is required; locale and launcher are optional.
identifyCoperaOmni('identify', identity)Set the visitor identity. Prefer { identityToken } for signed-in users; { name, email } supports unverified visitor details.
logoutCoperaOmni('logout')Clear the current identity before a user signs out or another user takes over the page.
destroyCoperaOmni('destroy')Remove the iframe, launcher, timers, listeners, and in-memory credentials.
openCoperaOmni('open')Open the chat panel.
closeCoperaOmni('close')Close the chat panel.
toggleCoperaOmni('toggle')Toggle the panel between open and closed.
setLauncherVisibleCoperaOmni('setLauncherVisible', visible)Show or hide the built-in launcher without destroying the widget.
updateCoperaOmni('update', { locale })Change the live widget locale.
onCoperaOmni('on', eventName, callback)Subscribe to an event. The live runtime returns an unsubscribe function.
offCoperaOmni('off', eventName, callback)Remove the same callback previously passed to on.

Le opzioni init supportate sono:

OptionTypeDefaultDescription
channelKeystringRequiredPublic source key copied from Configure & install.
localestring"en"BCP 47 locale for the widget UI, such as "en" or "pt-BR".
launcher"default" | "custom""default"Use "custom" to suppress Copera's launcher and control the panel yourself.

Eventi

Ogni callback di evento riceve un oggetto il cui name identifica l'evento.

EventPayloadWhen it fires
ready{ name: 'ready' }The iframe is ready and has dispatched its initial state. This does not prove that backend initialization succeeded.
open{ name: 'open' }The panel opens.
close{ name: 'close' }The panel closes.
identityRequired{ name: 'identityRequired' }A closed conversation is being restarted on a source that requires the visitor to be verified again.
unreadCount{ name: 'unreadCount', count: number }The unread message count changes.
conversationStarted{ name: 'conversationStarted', conversationId: string }A conversation starts and its ID becomes available.

Aggiorna un badge custom e registra l'inizio di una conversazione:

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('Omni conversation started', event.conversationId);
}

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

// When this page component is removed:
CoperaOmni('off', 'unreadCount', handleUnread);
CoperaOmni('off', 'conversationStarted', handleConversationStarted);

Tieni il riferimento al callback se intendi chiamare off; una nuova funzione inline non è lo stesso listener.

Usa gli eventi di lifecycle per tenere sincronizzata la UI host:

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 () {
// Ask the signed-in host application to refresh its identity token.
void identifyCurrentUser();
});

Identità del visitatore

Scegli quanto sai di ciascun visitatore. I visitatori anonimi e pre-chat non richiedono backend; i visitatori verificati usano un token a breve durata emesso dal server.

Lascia Require verified visitor identity spento. Un visitatore può iniziare senza dati di identità. Copera mantiene la widget session del browser associata alla conversazione.

Chiamare identify con { name, email } fornisce dettagli visitatore non verificati. Per l'identità di account autenticato, usa invece { identityToken } — descritto di seguito.

Identità verificata sicura

L'identità verificata ha tre confini:

  1. Copera emette una server API key legata alla source con prefisso cp_omni_sk_.
  2. Il backend invia a Copera un identificatore cliente stabile e riceve un identity token di cinque minuti.
  3. Il browser riceve solo il token a breve durata e lo passa al widget.
Non esporre mai la server API key

La key cp_omni_sk_… va solo nello store di secret del backend. Non metterla mai in HTML, JavaScript browser, un'app mobile, log, proprietà analytics o un repository pubblico. Il channelKey pubblico e la server API key privata servono scopi diversi e non sono intercambiabili.

Crea una server key legata alla source

Apri il pannello Configure & install della source widget. Sotto Server API keys, seleziona Create server key, nominala per un backend o ambiente e copiala immediatamente — viene mostrata una sola volta. Sono supportate più key attive, il che consente la rotazione senza condividere una credenziale tra ambienti.

Memorizzala come variabile d'ambiente solo-backend, ad esempio COPERA_OMNI_SERVER_KEY.

Emetti un token dal backend

Il backend chiama l'endpoint identity-token con la server key:

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

Il body della request accetta:

FieldRequiredDescription
externalIdYesAn opaque, stable, non-PII identifier for the signed-in customer, scoped to your application. Use the same value on future visits.
nameNoCurrent display name, from your trusted account record.
emailNoCurrent email address, from your trusted account record.

La server key lega già la richiesta a un workspace e a una source web-widget; non inviare un workspace ID, source ID, channel ID o channelKey in questa request. Vedi il riferimento API Create Omni identity token per lo schema e le response esatti.

La route Node.js seguente illustra il pattern same-origin. Assume che l'applicazione abbia già autenticato la request e reso l'utente autenticato disponibile come 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: 'Sign in required' });
}

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: 'Unable to start support chat' });
}

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

Per lo stesso externalId stabile entro quella source widget, Copera crea il contact la prima volta e riusa lo stesso contact nelle sessioni verificate successive. Usa un valore opaco creato per l'applicazione. Non usare un display name, un indirizzo email, un numero di telefono, uno username, un database ID sequenziale o un altro valore direttamente identificante o mutabile.

Fetch dal browser, poi identify

Espone la route sulla stessa origin dell'applicazione, richiedi la sessione autenticata normale dell'applicazione e le protezioni CSRF, e restituisci solo il token a breve durata:

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(`Omni identity request failed: ${response.status}`);
}

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

CoperaOmni('init', { channelKey: 'YOUR_CHANNEL_KEY' });
void identifyCurrentUser().catch(function (error) {
console.error('Unable to identify the Omni visitor', error);
});

Gli identity token scadono cinque minuti dopo l'emissione. Emittili on demand e usali immediatamente; non persistirli in local storage né trattarli come un login token long-lived.

Cambio di utente sulla stessa pagina

Chiama e attendi CoperaOmni('logout') prima di identificare un utente autenticato diverso nella stessa pagina browser. Al sign-out dell'applicazione, chiama logout anche se intendi mantenere disponibile la chat anonima. Questo evita che l'identità di un cliente si trascini nella sessione di un altro.

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

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

Quando un visitatore riavvia una conversazione chiusa e Require verified visitor identity è abilitato, il widget emette identityRequired così l'host può verificare di nuovo il visitatore. Richiedi un token fresco e chiama identify; non fare fallback a name e email forniti dal browser come se fossero verificati. Per la visita autenticata iniziale, identifica il visitatore in modo proattivo dopo init come mostrato sopra.

Sicurezza browser-origin

Browser origin (recommended) controlla la host page di embedding rispetto alle Allowed origins della source e stabilisce una embed session origin-bound a breve durata. Aggiungi l'origin della pagina che ospita il widget, come https://support.example.comnon https://widget.copera.ai. Configura origin esatte, incluso schema e porta quando presenti:

Page URLAllowed origin
https://www.example.com/pricinghttps://www.example.com
https://app.example.com/supporthttps://app.example.com
http://localhost:3000/accounthttp://localhost:3000

Path, query, fragment, username e password non fanno parte di un'origin. Aggiungi ciascun subdomain separatamente. Preferisci HTTPS fuori dallo sviluppo locale.

Scegli Browser origin (recommended) per i nuovi deployment e configura esplicitamente ogni origin consentita. Quando aggiungi o rimuovi un dominio di produzione, aggiorna Allowed origins prima di deployare l'embed lì. Rimuovere un'origin impedisce nuove embed session da quell'origin.

Rotazione e revoca

Tratta la public embed key e le server API key come credenziali separate:

ActionImmediate effectFollow-up
Regenerate keyExisting snippets using the old channelKey stop working.Replace the key in every embed.
Revoke a server API keyToken-minting requests using that cp_omni_sk_… key fail immediately.Deploy a replacement key first if the integration must remain available.

Per una rotazione server-key a zero-downtime, crea una seconda key, deployala sul backend, conferma che il valore Last used si aggiorni, poi revoca la vecchia key. Usa key separate per production, staging e ciascun backend indipendente.

Locale e lifecycle

Imposta la locale iniziale in init, poi usa update se il visitatore cambia lingua:

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

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

Per una single-page application:

  • Chiama init una sola volta per l'integrazione widget montata.
  • Iscriviti con on e rimuovi i listener con off quando il componente proprietario unmounta.
  • Chiama logout quando l'utente dell'applicazione fa sign-out o cambia.
  • Chiama destroy quando l'integrazione widget stessa viene rimossa permanentemente o quando ti serve intenzionalmente un'istanza fresca.

Risoluzione dei problemi

Lo script del widget non si carica

Proteggi il caricamento dello script. Lo snippet CDN diretto può rilevare un fallimento di network o CSP con l'evento error dell'elemento 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('The Copera Omni widget could not be loaded.');
};
d.head.appendChild(s);
})(window, document);
CoperaOmni('init', { channelKey: 'YOUR_CHANNEL_KEY' });
</script>

Se la request è bloccata, controlla la Content Security Policy e conferma che l'origin della host page sia in Allowed origins.

Come confermo che l'inizializzazione è riuscita?

init, identify, logout e destroy possono restituire promise dopo che il runtime live è installato. Attendi le transition di identità e sessione e gestisci il rejection. Quando chiami il dispatcher live direttamente o usi il wrapper tipizzato, attendi init() per confermare l'inizializzazione backend.

I comandi messi in coda prima che il runtime si installi sono fire-and-forget; l'evento ready conferma solo che l'iframe è pronto e che il suo stato iniziale è stato dispatchato — non prova che l'inizializzazione backend sia riuscita.

Le request di identity-token falliscono
  • Restituisci un errore generico dal backend; non inoltrare mai la server key o il body di response del provider al browser.
  • Ritenta solo i fallimenti server transienti con backoff limitato.
  • Emetti un nuovo token dopo la scadenza invece di riprodurre un vecchio token.
  • Tratta un 401 dall'endpoint token come server key mancante, malformata o revocata, e ruotala o sostituiscila.
  • Tratta un 403 come source widget non disponibile, e verifica che la source sia connessa e non sospesa.

Content Security Policy

Allowlist delle origin Copera per una CSP strict

Se il sito usa Content Security Policy (CSP), consenti le origin Copera minime richieste nelle direttive rilevanti:

  • script-src: https://widget.copera.ai per widget.js.
  • frame-src: https://widget.copera.ai per l'iframe del chat panel.
  • connect-src: https://api.copera.ai per le request fatte dalla host page.
  • style-src: Il runtime widget corrente crea elementi style e attributi style e non supporta un'alternativa nonce o hash. L'integrazione CSP strict richiede quindi 'unsafe-inline' in style-src solo — non aggiungerlo mai a script-src.
  • La policy deve anche consentire il bootstrap inline mostrato in Quick embed. Se la policy blocca gli script inline, sposta il bootstrap in un file esterno consentito o autorizzalo con la policy nonce o hash del sito. Non indebolire la policy con 'unsafe-inline' in script-src.
  • Configura l'origin della host page di embedding sotto Allowed origins, ad esempio https://support.example.com — non https://widget.copera.ai. Il permesso CSP non sostituisce il check origin di Copera.

Dopo aver cambiato la CSP, testa sotto enforcement CSP: verifica il launcher, l'apertura del panel, l'avvio di una conversazione, la ricezione di un aggiornamento unread e l'identità verificata nella console browser senza request bloccate.

Wrapper tipizzato e runtime CDN

Il runtime CDN a https://widget.copera.ai/widget.js è il widget stesso ed è tutto ciò di cui un'integrazione HTML semplice ha bisogno. @copera/omni-widget-sdk è un wrapper tipizzato opzionale per applicazioni TypeScript: inietta lo stesso runtime CDN una volta, bufferizza le chiamate early ed espone una facciata tipizzata per gli stessi comandi ed eventi. Non sostituisce il widget CDN né cambia il flusso di identità server.

Usa gli esempi di runtime diretto in questa guida a meno che l'applicazione non consumi già il wrapper tipizzato. L'installazione del package e le istruzioni alternative package-CDN sono intenzionalmente fuori da questa guida di embed.

Domande frequenti

Il widget web Copera Omni è gratuito?

Il web widget è gratuito. I numeri WhatsApp collegati a un channel Omni sono add-on a pagamento, e rimuovere una source WhatsApp o eliminare il suo channel non annulla lo slot del numero acquistato. Riduci la quantità acquistata separatamente in Workspace Billing.

Il channelKey del widget è sicuro da usare nel codice browser?

Sì. Il channelKey è la chiave pubblica di una source web-widget e va nell'embed code. Non è un channel ID, un source ID o una server API key privata cp_omni_sk_…. Rigenerare il channelKey interrompe immediatamente gli embed che usano ancora il vecchio valore.

Come identifico in modo sicuro un visitatore autenticato?

Autentica il visitatore nel backend dell'applicazione, scambia la key cp_omni_sk_… legata alla source con un identity token di cinque minuti e restituisci al browser solo quel token a breve durata. Poi chiama CoperaOmni('identify', { identityToken }). Non esporre mai la server API key al browser o a un client mobile.

Come restringo quali siti possono incorporare il widget?

Scegli Browser origin (recommended) e aggiungi ogni origin esatta consentita, incluso schema e porta quando presenti, ad Allowed origins. Aggiungi i subdomain separatamente. I permessi Content Security Policy non sostituiscono il check allowed-origin di Copera.

Documentazione correlata