Aller au contenu principal

Widget de chat web Copera Omni : configuration, SDK et identité

Le widget web Copera Omni ajoute le chat web à votre site et route chaque conversation vers un channel Omni — une boîte de réception partagée qui peut recevoir des conversations de plusieurs sources à la fois, comme un ou plusieurs widgets web et numéros WhatsApp, afin que votre équipe travaille sur toutes dans un seul endroit.

Ce guide vous emmène d'une installation en deux minutes à une intégration de niveau production : l'embed à copier-coller, l'API de commandes CoperaOmni pour des lanceurs personnalisés, la sécurité d'origine navigateur, et le flux sécurisé pour identifier les visiteurs connectés sans jamais exposer de clé serveur dans le navigateur.

Sources gratuites vs payantes

Un channel Omni peut combiner plusieurs sources. Le widget web est la gratuite ; WhatsApp est un add-on payant.

Widget web — Gratuit

Ajoutez autant de sources de widget web que nécessaire sans frais. Tout dans ce guide utilise le widget web gratuit.

WhatsApp — Add-on payant

Connectez des numéros WhatsApp au même channel Omni comme add-ons payants, afin que les conversations web et WhatsApp atterrissent dans une seule boîte de réception.

Retirer une source n'annule pas un numéro acheté

Retirer une source WhatsApp ou supprimer un channel Omni n'annule pas son slot de numéro acheté. Pour arrêter de payer un slot, réduisez la quantité achetée séparément dans Workspace Billing.

Démarrage rapide

Deux minutes pour un widget en direct.

Ajouter une source Web widget

Dans Copera, ouvrez (ou créez) un channel Omni, allez dans Settings → Add source, et choisissez Web widget — Copera étiquette cette source comme Free. Puis copiez le channelKey affiché sous Configure & install.

Installer le snippet avant </body>

Choisissez Quick embed ou JavaScript SDK ci-dessous, collez-le dans votre page, et remplacez YOUR_CHANNEL_KEY par la clé que vous avez copiée.

Recharger votre page

Le lanceur flottant de Copera apparaît à la position que vous avez configurée. Ouvrez-le pour démarrer une conversation.

Placez ce snippet complet une fois, juste avant la balise fermante </body>. Il charge le runtime CDN de façon asynchrone, initialise la source, et affiche le lanceur flottant de 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>

C'est tout ce dont un site HTML simple a besoin. Pour contrôler le panneau depuis votre propre bouton au lieu du lanceur flottant, passez à l'onglet JavaScript SDK.

Clé publique, pas un ID de channel

Le channelKey généré est la clé publique pour cette source de widget web spécifique. Il est sûr de le placer dans le code navigateur. Ce n'est pas l'ID du channel Omni ni l'ID de source, et il ne doit pas être remplacé par l'un ou l'autre.

Régénérer la clé casse les embeds existants

Si vous sélectionnez Regenerate key, l'ancien channelKey cesse de fonctionner. Remplacez-le partout où le widget est intégré.

Configurer le widget

Le démarrage rapide utilise les défauts. Ouvrez les Settings (ou Configure & install) de la source du widget pour adapter l'expérience complète avant de passer en production.

Créer ou ouvrir un channel Omni

Créez un channel en utilisant le type de channel Omni, ou ouvrez un existant. Un seul channel Omni peut recevoir des conversations de plusieurs sources.

Ajouter la source web widget

Ouvrez les Settings du channel, sélectionnez Add source, puis choisissez Web widget. Copera étiquette cette source comme Free.

Configurer l'expérience

Saisissez un Display name, choisissez la Primary color et la Launcher position, et définissez optionnellement un Greeting message. Vous pouvez aussi activer Show a pre-chat form pour les visiteurs anonymes.

Sécuriser l'embed

Pour une nouvelle intégration, choisissez Browser origin (recommended) sous Embed security. Ajoutez chaque origine exacte de site qui peut intégrer le widget à Allowed origins, en appuyant sur Entrée après chacune — par exemple, https://www.example.com et https://app.example.com.

Choisir le comportement d'identité

Laissez Require verified visitor identity désactivé pour autoriser les conversations anonymes ou pré-chat. Activez-le lorsque votre site appellera toujours identify avec un token d'identité émis par le serveur. Le formulaire pré-chat et l'identité vérifiée requise ne peuvent pas être activés ensemble.

Créer et installer

Sélectionnez Create widget. Sur l'écran de succès, copiez Quick embed pour le lanceur intégré ou sélectionnez JavaScript SDK pour un lanceur personnalisé. Vous pouvez revenir à la source et sélectionner Configure & install plus tard.

ParamètreCe qu'il contrôleDéfaut
Display nameLe nom affiché en haut du panneau de chat.Nom de la source
Primary colorLa couleur d'accent du lanceur et du panneau.Accent du workspace
Launcher positionDans quel coin se trouve le lanceur flottant.Bas-droite
Greeting messageUn premier message optionnel affiché à l'ouverture du panneau.Aucun
Show a pre-chat formDemande des détails aux visiteurs anonymes avant le début de la conversation.Off
Embed securityComment Copera décide quelles pages peuvent intégrer le widget.Browser origin
Require verified visitor identityBloque les chats anonymes et pré-chat ; exige un token d'identité émis par le serveur.Off

API de commandes JavaScript

https://widget.copera.ai/widget.js installe la fonction de commande globale CoperaOmni(command, ...args). Les appels faits via le snippet de file d'attente avant la fin du chargement du runtime sont mis en tampon et rejoués dans l'ordre.

Commandes

CommandeSignatureRôle
initCoperaOmni('init', config)Initialise le widget. config.channelKey est requis ; locale et launcher sont optionnels.
identifyCoperaOmni('identify', identity)Définit l'identité du visiteur. Préférez { identityToken } pour les utilisateurs connectés ; { name, email } prend en charge des détails de visiteur non vérifiés.
logoutCoperaOmni('logout')Efface l'identité en cours avant qu'un utilisateur se déconnecte ou qu'un autre prenne la page.
destroyCoperaOmni('destroy')Supprime l'iframe, le lanceur, les timers, les écouteurs et les identifiants en mémoire.
openCoperaOmni('open')Ouvre le panneau de chat.
closeCoperaOmni('close')Ferme le panneau de chat.
toggleCoperaOmni('toggle')Bascule le panneau entre ouvert et fermé.
setLauncherVisibleCoperaOmni('setLauncherVisible', visible)Affiche ou masque le lanceur intégré sans détruire le widget.
updateCoperaOmni('update', { locale })Change la locale live du widget.
onCoperaOmni('on', eventName, callback)S'abonne à un événement. Le runtime live renvoie une fonction de désabonnement.
offCoperaOmni('off', eventName, callback)Retire le même callback précédemment passé à on.

Les options init prises en charge sont :

OptionTypeDéfautDescription
channelKeystringRequisClé publique de source copiée depuis Configure & install.
localestring"en"Locale BCP 47 pour l'UI du widget, comme "en" ou "pt-BR".
launcher"default" | "custom""default"Utilisez "custom" pour supprimer le lanceur de Copera et contrôler le panneau vous-même.

Événements

Chaque callback d'événement reçoit un objet dont le name identifie l'événement.

ÉvénementCharge utileQuand il se déclenche
ready{ name: 'ready' }L'iframe est prêt et a dispatché son état initial. Cela ne prouve pas que l'initialisation backend a réussi.
open{ name: 'open' }Le panneau s'ouvre.
close{ name: 'close' }Le panneau se ferme.
identityRequired{ name: 'identityRequired' }Une conversation fermée est redémarrée sur une source qui exige que le visiteur soit à nouveau vérifié.
unreadCount{ name: 'unreadCount', count: number }Le nombre de messages non lus change.
conversationStarted{ name: 'conversationStarted', conversationId: string }Une conversation démarre et son ID devient disponible.

Mettez à jour un badge personnalisé et enregistrez un démarrage de conversation :

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);

Gardez la référence du callback si vous prévoyez d'appeler off ; une nouvelle fonction inline n'est pas le même écouteur.

Utilisez les événements de cycle de vie pour garder l'UI hôte synchronisée :

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é du visiteur

Choisissez à quel point vous connaissez chaque visiteur. Les visiteurs anonymes et pré-chat n'ont pas besoin de backend ; les visiteurs vérifiés utilisent un token de courte durée émis par le serveur.

Laissez Require verified visitor identity désactivé. Un visiteur peut commencer sans données d'identité. Copera garde la session widget du navigateur associée à la conversation.

Appeler identify avec { name, email } fournit des détails de visiteur non vérifiés. Pour l'identité de compte authentifié, utilisez plutôt { identityToken } — décrit ensuite.

Identité vérifiée sécurisée

L'identité vérifiée a trois frontières :

  1. Copera émet une clé d'API serveur liée à la source avec le préfixe cp_omni_sk_.
  2. Votre backend envoie un identifiant client stable à Copera et reçoit un token d'identité de cinq minutes.
  3. Votre navigateur ne reçoit que le token de courte durée et le passe au widget.
N'exposez jamais la clé d'API serveur

La clé cp_omni_sk_… n'appartient que dans le magasin de secrets de votre backend. Ne la placez jamais dans du HTML, du JavaScript navigateur, une app mobile, des logs, des propriétés analytics, ou un dépôt public. La channelKey publique et la clé d'API serveur privée servent des buts différents et ne sont pas interchangeables.

Créer une clé serveur liée à la source

Ouvrez le panneau Configure & install de la source du widget. Sous Server API keys, sélectionnez Create server key, nommez-la pour un backend ou environnement, et copiez-la immédiatement — elle n'est affichée qu'une seule fois. Plusieurs clés actives sont prises en charge, ce qui permet la rotation sans partager un identifiant entre environnements.

Stockez-la comme variable d'environnement backend uniquement, par exemple COPERA_OMNI_SERVER_KEY.

Créer un token depuis votre backend

Votre backend appelle l'endpoint de token d'identité avec la clé serveur :

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

Le corps de la requête accepte :

ChampRequisDescription
externalIdOuiUn identifiant opaque, stable, non-PII pour le client connecté, scopé à votre application. Utilisez la même valeur lors des visites futures.
nameNonNom d'affichage actuel, depuis votre enregistrement de compte de confiance.
emailNonAdresse e-mail actuelle, depuis votre enregistrement de compte de confiance.

La clé serveur lie déjà la requête à un workspace et une source de widget web ; n'envoyez pas d'ID de workspace, d'ID de source, d'ID de channel ou de channelKey dans cette requête. Voir la référence API Create Omni identity token pour le schéma exact et les réponses.

La route Node.js suivante illustre le motif same-origin. Elle suppose que votre application a déjà authentifié la requête et rendu l'utilisateur connecté disponible comme 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 });
}

Pour le même externalId stable au sein de cette source de widget, Copera crée le contact la première fois et réutilise ce même contact lors des sessions vérifiées futures. Utilisez une valeur opaque créée pour votre application. N'utilisez pas un nom d'affichage, une adresse e-mail, un numéro de téléphone, un nom d'utilisateur, un ID de base de données séquentiel, ou une autre valeur directement identifiante ou changeante.

Récupérer depuis le navigateur, puis identifier

Exposez la route sur la même origine que votre application, exigez la session authentifiée normale de l'application et les protections CSRF, et ne renvoyez que le token de courte durée :

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);
});

Les tokens d'identité expirent cinq minutes après leur création. Créez-les à la demande et utilisez-les immédiatement ; ne les persistez pas dans le local storage et ne les traitez pas comme un token de connexion de longue durée.

Changer d'utilisateur sur la même page

Appelez et attendez CoperaOmni('logout') avant d'identifier un utilisateur connecté différent dans la même page navigateur. Lors de la déconnexion de l'application, appelez logout même si vous prévoyez de garder le chat anonyme disponible. Cela empêche l'identité d'un client de se reporter dans la session d'un autre.

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

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

Lorsqu'un visiteur redémarre une conversation fermée et que Require verified visitor identity est activé, le widget émet identityRequired pour que l'hôte puisse à nouveau vérifier le visiteur. Demandez un token frais et appelez identify ; ne retombez pas sur name et email fournis par le navigateur comme s'ils étaient vérifiés. Pour la visite connectée initiale, identifiez le visiteur de façon proactive après init comme montré ci-dessus.

Sécurité d'origine navigateur

Browser origin (recommended) vérifie la page hôte d'intégration contre les Allowed origins de la source et établit une session d'embed liée à l'origine de courte durée. Ajoutez l'origine de la page qui héberge le widget, comme https://support.example.compas https://widget.copera.ai. Configurez des origines exactes, y compris le schéma et le port lorsque présents :

URL de la pageOrigine autorisée
https://www.example.com/pricinghttps://www.example.com
https://app.example.com/supporthttps://app.example.com
http://localhost:3000/accounthttp://localhost:3000

Les chemins, requêtes, fragments, noms d'utilisateur et mots de passe ne font pas partie d'une origine. Ajoutez chaque sous-domaine séparément. Préférez HTTPS hors développement local.

Choisissez Browser origin (recommended) pour les nouveaux déploiements et configurez explicitement chaque origine autorisée. Lorsque vous ajoutez ou retirez un domaine de production, mettez à jour Allowed origins avant d'y déployer l'embed. Retirer une origine empêche de nouvelles sessions d'embed depuis cette origine.

Rotation et révocation

Traitez la clé d'embed publique et les clés d'API serveur comme des identifiants séparés :

ActionEffet immédiatSuite
Regenerate keyLes snippets existants utilisant l'ancien channelKey cessent de fonctionner.Remplacez la clé dans chaque embed.
Revoke une clé d'API serveurLes requêtes de création de token utilisant cette clé cp_omni_sk_… échouent immédiatement.Déployez d'abord une clé de remplacement si l'intégration doit rester disponible.

Pour une rotation de clé serveur sans interruption, créez une seconde clé, déployez-la sur le backend, confirmez que sa valeur Last used se met à jour, puis révoquez l'ancienne clé. Utilisez des clés séparées pour la production, le staging et chaque backend indépendant.

Locale et cycle de vie

Définissez la locale initiale dans init, puis utilisez update si le visiteur change de langue :

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

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

Pour une application monopage :

  • Appelez init une fois pour l'intégration de widget montée.
  • Abonnez-vous avec on et retirez les écouteurs avec off lorsque le composant propriétaire se démonte.
  • Appelez logout lorsque l'utilisateur de l'application se déconnecte ou change.
  • Appelez destroy lorsque l'intégration du widget elle-même est définitivement retirée ou lorsque vous avez intentionnellement besoin d'une instance fraîche.

Dépannage

Le script du widget ne se charge pas

Protégez le chargement du script. Le snippet CDN direct peut détecter un échec réseau ou CSP avec l'événement error de l'élément 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>

Si la requête est bloquée, vérifiez votre Content Security Policy et confirmez que l'origine de la page hôte est dans Allowed origins.

Comment confirmer que l'initialisation a réussi ?

init, identify, logout et destroy peuvent renvoyer des promesses après l'installation du runtime live. Attendez les transitions d'identité et de session et gérez le rejet. Lorsque vous appelez le dispatcher live directement ou utilisez le wrapper typé, attendez init() pour confirmer l'initialisation backend.

Les commandes mises en file avant l'installation du runtime sont fire-and-forget ; l'événement ready confirme seulement que l'iframe est prêt et que son état initial a été dispatché — il ne prouve pas que l'initialisation backend a réussi.

Les requêtes de token d'identité échouent
  • Renvoyez une erreur générique depuis votre backend ; ne transmettez jamais la clé serveur ni le corps de réponse du fournisseur au navigateur.
  • Ne réessayez que les échecs serveur transitoires avec un backoff borné.
  • Créez un nouveau token après expiration au lieu de rejouer un ancien token.
  • Traitez un 401 de l'endpoint de token comme une clé serveur manquante, mal formée ou révoquée, et faites-la tourner ou remplacez-la.
  • Traitez un 403 comme une source de widget indisponible, et vérifiez que la source est connectée et non suspendue.

Content Security Policy

Mettre les origines Copera en allowlist pour une CSP stricte

Si votre site utilise Content Security Policy (CSP), autorisez les origines Copera minimales requises dans les directives pertinentes :

  • script-src : https://widget.copera.ai pour widget.js.
  • frame-src : https://widget.copera.ai pour l'iframe du panneau de chat.
  • connect-src : https://api.copera.ai pour les requêtes faites par la page hôte.
  • style-src : Le runtime widget actuel crée des éléments de style et des attributs de style et ne prend pas en charge d'alternative nonce ou hash. Une intégration CSP stricte exige donc 'unsafe-inline' dans style-src uniquement — ne l'ajoutez jamais à script-src.
  • Votre politique doit aussi autoriser le bootstrap inline montré dans Quick embed. Si votre politique bloque les scripts inline, déplacez le bootstrap dans un fichier externe autorisé ou autorisez-le avec la politique nonce ou hash de votre site. N'affaiblissez pas la politique avec 'unsafe-inline' dans script-src.
  • Configurez l'origine de la page hôte d'intégration sous Allowed origins, par exemple https://support.example.com — pas https://widget.copera.ai. La permission CSP ne remplace pas le contrôle d'origine de Copera.

Après avoir modifié la CSP, testez sous application CSP : vérifiez le lanceur, l'ouverture du panneau, le démarrage d'une conversation, la réception d'une mise à jour non lue, et l'identité vérifiée dans la console navigateur sans requêtes bloquées.

Wrapper typé et runtime CDN

Le runtime CDN à https://widget.copera.ai/widget.js est le widget lui-même et est tout ce dont une intégration HTML simple a besoin. @copera/omni-widget-sdk est un wrapper typé optionnel pour les applications TypeScript : il injecte le même runtime CDN une fois, met en tampon les appels précoces, et expose une façade typée pour les mêmes commandes et événements. Il ne remplace pas le widget CDN et ne change pas le flux d'identité serveur.

Utilisez les exemples de runtime direct de ce guide sauf si votre application consomme déjà le wrapper typé. L'installation du package et les instructions de package-CDN alternatives sont volontairement hors de ce guide d'embed.

Questions fréquentes

Le widget web Copera Omni est-il gratuit ?

Le widget web est gratuit. Les numéros WhatsApp connectés à un channel Omni sont des add-ons payants, et retirer une source WhatsApp ou supprimer son channel n'annule pas le slot de numéro acheté. Réduisez la quantité achetée séparément dans Workspace Billing.

Le channelKey du widget est-il sûr à utiliser dans le code navigateur ?

Oui. Le channelKey est la clé publique d'une source de widget web et appartient dans le code d'embed. Ce n'est pas un ID de channel, un ID de source, ni une clé d'API serveur privée cp_omni_sk_…. Régénérer le channelKey arrête immédiatement les embeds qui utilisent encore l'ancienne valeur.

Comment identifier un visiteur connecté de façon sécurisée ?

Authentifiez le visiteur dans le backend de votre application, échangez la clé cp_omni_sk_… liée à la source contre un token d'identité de cinq minutes, et ne renvoyez que ce token de courte durée au navigateur. Puis appelez CoperaOmni('identify', { identityToken }). N'exposez jamais la clé d'API serveur au navigateur ou à un client mobile.

Comment restreindre les sites qui peuvent intégrer le widget ?

Choisissez Browser origin (recommended) et ajoutez chaque origine exacte autorisée, y compris son schéma et son port lorsque présents, à Allowed origins. Ajoutez les sous-domaines séparément. Les permissions Content Security Policy ne remplacent pas le contrôle d'origine autorisée de Copera.

Documentation associée