Widget B2C — visiteur invité et entreprise
Cette section couvre les intégrations où le widget reste en session invité :
- site public, visiteur inconnu : script et formulaire de contact seulement
- site ou portail qui connaît déjà le compte :
init()avec le profil et les données d'entreprise, formulaire sauté lorsque les données suffisent, contact lié à l'entreprise
L'historique personnel sur un autre navigateur ou appareil est une autre intégration. Voir Widget B2B. Contrat complet des champs, changement de compte dans une SPA, CSP et provisioning : Intégration technique.
Associer une entreprise n'autorise pas l'historique d'une autre personne. Un utilisateur authentifié sur le site reste un invité du widget tant que vous n'envoyez pas external_user_id avec un restore_id valide.
Ce que vous obtenez
- Un bouton flottant, ou une conversation intégrée dans un conteneur de la page
- Un formulaire initial pour les inconnus, avec les libellés Téléphone et Nom. Dans
init()les champs sontphoneetname - Une session invité enregistrée par le loader dans le même navigateur, séparée par clé de widget. Si
localStorageest bloqué, la continuité peut rester sur la page courante - Si vous envoyez
external_id, Quoting24 cherche une entreprise avec le mêmeweb_code. Aveccompany_nameen plus, il peut créer l'entreprise manquante et y lier le contact - Tickets et réponses dans Quoting24, comme sur les autres canaux
La session invité relit sa conversation la plus récente même après la fermeture de l'onglet. Elle ne suit pas la personne sur un autre navigateur.
1. Prérequis dans Quoting24
- Canal Widget actif dans Paramètres → Canaux
- Logo, couleur, position, accueil, bienvenue et hors horaires configurés
- Domaines autorisés à jour, y compris le recettage et
localhost - Code d'intégration copié depuis la configuration du canal : URL du script et clé publique
Utilisez l'hôte et la clé du même environnement. Dans les exemples, remplacez HOTE_WIDGET et CLE_PUBLIQUE_WIDGET.
Les domaines sont des noms d'hôte, sans https://, port, chemin ni *.. example.com inclut les sous-domaines. Liste vide : aucune restriction. En local, servez la page en HTTP, pas en file://.
Le company_name de init() est la raison sociale du client. Ce n'est pas le titre du widget et il ne se configure pas depuis ce payload.
2. Installer le bouton flottant
Collez le script une seule fois, avant </body> :
Le bouton apparaît après le chargement des réglages graphiques. Un nouveau visiteur voit le formulaire de contact. Celui qui revient dans le même navigateur reprend la session invité, si le stockage est disponible.
Le script expose un unique window.Quoting24Widget.
3. Intégrer la conversation dans la page
Créez le conteneur avant le script et donnez-lui une hauteur explicite :
<section aria-labelledby="titre-assistance">
<h2 id="titre-assistance">Assistance</h2>
<div id="chat-assistance" style="width: 100%; height: 600px;"></div>
</section>
<script
src="https://HOTE_WIDGET/assets/widget/script.js?key=CLE_PUBLIQUE_WIDGET&mode=embedded&target=chat-assistance"
async
></script>
targetest l'ID de l'élément, sans#- L'iframe remplit le conteneur
- Il n'y a pas de bouton flottant
open(),close()ettoggle()n'ont pas d'effet- Dans ce mode, le site décide de la hauteur et de la largeur. En mode flottant, sur mobile, la conversation peut occuper le viewport
Le mode intégré, à lui seul, n'active pas la restauration de l'historique.
4. Envoyer le profil du client
Lorsque le site connaît le compte, envoyez le profil après le chargement du loader. Les champs sont des chaînes. Omettez ceux qui sont inconnus : n'envoyez pas null, des ID numériques ni un e-mail vide.
window.Quoting24Widget.init({
external_id: "52",
company_name: "Ricambi Stella S.r.l.",
name: "mario.rossi",
phone: "+393331234567",
email: "amministrazione@ricambi-stella.example",
});
| Donnée dans le site ou le logiciel de gestion | Champ | Signification |
|---|---|---|
Référence stable de l'entreprise, la même valeur importée dans web_code |
external_id |
Comparaison exacte avec companies.web_code, dans l'organisation du widget |
| Raison sociale | company_name |
Utilisée s'il faut créer l'entreprise |
| Nom de la personne ou de l'utilisateur | name |
Nom affiché sur le contact |
| E-mail du compte | email |
Enregistré sur l'entreprise seulement lorsque l'entreprise est créée |
| Téléphone, si vous le connaissez | phone |
Numéro du contact. Préférez le format international, par exemple +393331234567 |
Ce payload n'envoie ni external_user_id ni restore_id. Gardez name et company_name séparés : ne concaténez pas la raison sociale au nom d'utilisateur pour obtenir l'association. Le champ public est external_id. N'envoyez pas web_code, l'UUID interne de Quoting24 ni companies.code.
Le formulaire affiche Nom et Téléphone. Dans init() ces champs s'appellent name et phone. L'e-mail s'appelle email. Nom, Téléphone et Email ne sont pas des clés : le loader les ignore, comme il ignore web_code à la place de external_id.
Exemples
Nom et téléphone, les mêmes données que le formulaire. La conversation démarre et ne cherche pas d'entreprise.
Profil avec entreprise. name est la personne, phone le numéro du contact, email est écrit sur l'entreprise seulement si cet appel la crée.
widget.init({
external_id: "52",
company_name: "Ricambi Stella S.r.l.",
name: "Mario Rossi",
phone: "+393331234567",
email: "mario.rossi@ricambi-stella.example",
});
E-mail seul. Une adresse valide dans email suffit pour ouvrir la session.
Si un champ dépasse les limites ou si l'e-mail est mal formé, la requête est refusée. Limites et comportement de chaque champ : Intégration technique.
Attendre le loader
Un script async peut ne pas encore être exécuté lorsque le code suivant appelle init(). Pour les données préremplies, utilisez un module de chargement à la place de la balise statique, importé une seule fois dans la structure principale :
// /assets/quoting24-loader.js
const widgetScriptUrl =
"https://HOTE_WIDGET/assets/widget/script.js?key=CLE_PUBLIQUE_WIDGET";
let widgetPromise;
export function loadWidget() {
if (window.Quoting24Widget) {
return Promise.resolve(window.Quoting24Widget);
}
if (widgetPromise) return widgetPromise;
widgetPromise = new Promise((resolve, reject) => {
const script = document.createElement("script");
script.id = "quoting24-widget-script";
script.src = widgetScriptUrl;
script.async = true;
script.onload = () => {
if (window.Quoting24Widget) resolve(window.Quoting24Widget);
else {
script.remove();
reject(new Error("API du widget indisponible"));
}
};
script.onerror = () => {
script.remove();
reject(new Error("Échec du chargement du widget"));
};
document.body.appendChild(script);
}).catch((error) => {
widgetPromise = undefined;
throw error;
});
return widgetPromise;
}
import { loadWidget } from "/assets/quoting24-loader.js";
const widget = await loadWidget();
widget.init({
external_id: "52",
company_name: "Ricambi Stella S.r.l.",
name: "mario.rossi",
phone: "+393331234567",
email: "amministrazione@ricambi-stella.example",
});
Importez le module depuis le bundler, ou chargez le fichier d'entrée avec <script type="module" src="/assets/assistance.js"></script>. Pour le mode intégré, ajoutez &mode=embedded&target=chat-assistance à l'URL et montez d'abord le conteneur.
loadWidget() signale seulement que l'API JavaScript est disponible. init() renvoie void : il met le profil en file si l'iframe n'est pas prêt et n'attend pas la session. Pour le résultat, utilisez isReady() et hasSessionError().
init() remplace le profil mémorisé. Il ne le fusionne pas avec le précédent. Passez tous les champs qui doivent rester.
Un changement de page dans une SPA ne demande ni un nouveau script ni un reset(). Au changement de personne ou de compte, et à la déconnexion, appelez reset() avant le nouveau profil : changer seulement les champs ne détache pas la session invité précédente. Schéma complet : Connexion, déconnexion et changement de compte.
5. Comment l'entreprise est associée ou créée
Quoting24 exécute ce flux à l'initialisation, même si le visiteur n'a pas encore envoyé de message :
- Avec un
external_idnon vide, il cherche une entreprise de la même organisation dont leweb_codeest égal à cette valeur - S'il la trouve, il lie le contact. Le nom et l'e-mail de l'entreprise existante restent inchangés
- S'il ne la trouve pas et qu'un
company_namenon vide est aussi présent, il crée l'entreprise avecname = company_name,web_code = external_idet l'e-mail éventuel, puis lie le contact - S'il ne peut ni trouver ni créer l'entreprise, il continue avec le profil disponible. Si cela ne suffit pas pour un nouvel invité, il affiche le formulaire. Les erreurs de base ou la limite de requêtes font échouer l'initialisation
| Données envoyées | Situation dans Quoting24 | Résultat |
|---|---|---|
external_id: "52", company_name: "Ricambi Stella S.r.l." |
web_code = "52" existe |
Utilise l'entreprise existante et n'en modifie pas le nom |
| Mêmes données, plus un e-mail valide | web_code = "52" n'existe pas |
Crée l'entreprise avec le code web 52, la raison sociale et l'e-mail, et associe le contact |
external_id: "52", name: "mario.rossi" |
Aucune correspondance | Démarre l'invité sans nouvelle association d'entreprise |
external_id: "52", sans autres données |
Une correspondance existe | Démarre l'invité associé à l'entreprise, avec le nom par défaut Visitatore |
external_id: "52", sans autres données |
Aucune correspondance | Affiche le formulaire de contact |
company_name sans external_id, plus name |
Quelconque | Démarre le visiteur. Ne cherche pas et ne crée pas d'entreprise |
La recherche n'utilise pas la raison sociale, l'e-mail, le téléphone, le numéro de TVA ni companies.code. "052" et "52" sont des valeurs différentes ; les espaces dans external_id ne sont pas retirés. Si vous importez le fichier clients avant, écrivez dans web_code la même valeur que le site enverra dans external_id. Voir aussi Entreprises → Code web.
Un nouvel invité démarre s'il y a au moins un nom, un téléphone, un e-mail valide ou un external_user_id, ou une entreprise trouvée ou créée via external_id. init({}) et company_name seul ne démarrent pas de session.
Pour un contact déjà lié, un nouveau code valide peut changer son entreprise. Omettre le code, ou en envoyer un qui ne se résout pas, n'efface pas l'association précédente. Le changement de personne ou de compte exige reset().
Limites
web_code n'est pas unique. Avec plusieurs correspondances, l'initialisation publique prend la première par date de création croissante. Des requêtes simultanées qui ne trouvent pas encore l'entreprise peuvent en créer plusieurs : la création n'est pas atomique et ne remplace pas un import ou une synchronisation depuis le logiciel de gestion.
La création implicite est limitée à 20 tentatives par fenêtre de 60 secondes et par adresse IP, dans le processus backend qui traite la requête. Au-delà, l'initialisation échoue avec TOO_MANY_REQUESTS : réessayez avec une attente, sans boucles continues de init().
Les données partent du navigateur et le visiteur peut les altérer. Le lien ne prouve pas l'appartenance à l'entreprise et n'accorde pas l'historique de l'entreprise. Envoyez company_name seulement si vous voulez autoriser cette création publique. Pour mettre à jour des entreprises déjà présentes, utilisez les outils de Quoting24 ou une intégration de gestion autorisée.
L'e-mail de l'initialisation publique n'est enregistré que sur la nouvelle entreprise. Il n'est pas écrit sur le contact et ne met pas à jour une entreprise déjà présente. Un téléphone déjà utilisé par un autre contact ne fusionne ni les contacts ni les conversations.
6. Comportement sur le site
| Situation | Comportement attendu |
|---|---|
| Premier visiteur, script seul | Bouton, puis formulaire, puis conversation |
init() avec un profil suffisant |
Formulaire sauté |
external_id déjà présent comme web_code |
Contact associé ; nom et e-mail de l'entreprise inchangés |
Nouvel external_id avec company_name |
Entreprise créée et contact associé |
Nouveau code et nom, sans company_name |
Conversation sans nouvelle entreprise |
| Nouveau code seul | Formulaire de contact |
| Raison sociale et nom seulement | Aucune recherche ni création par nom |
| Rechargement dans le même navigateur | Session invité reprise, si le stockage est disponible |
| Autre navigateur ou appareil | Nouvelle session invité |
| Hors horaires | Bannière hors horaires ; la saisie reste utilisable |
| Mobile, bouton flottant | La conversation peut occuper le viewport |
Pièces jointes : PDF, DOC, DOCX, JPG/JPEG, PNG. Maximum 10 MiB par fichier et 100 MiB de pièces référencées par conversation.
7. Contrôles utiles
Lorsque le bouton flottant est visible, vous pouvez relier un bouton du site à window.Quoting24Widget?.open().
| Méthode | Usage |
|---|---|
init(profile) |
Définit ou remplace le profil courant |
open() / close() / toggle() |
Widget flottant seulement. Fermer n'est pas une déconnexion |
isReady() |
Session visiteur démarrée. Reste faux sur le formulaire de contact |
hasSessionError() |
Erreur de session signalée par l'iframe |
reset() |
Efface le profil, la session locale, le credential invité enregistré et les non-lus de cette instance |
dispose() |
Démonte l'interface et les écouteurs. N'efface pas le credential invité enregistré ni l'objet API global |
N'attendez pas isReady() pour laisser un nouvel invité ouvrir le formulaire. Il n'y a pas d'événement public de disponibilité. Ces indicateurs ne décrivent pas tout l'état du réseau.
Liste de contrôle avant mise en production
- [ ] Hôte et clé du même environnement
- [ ] Domaines du site et du staging dans la liste, uniquement comme noms d'hôte
- [ ] Logo, couleur, accueil, bienvenue et hors horaires vérifiés
- [ ] Navigateur neuf, script seul : formulaire, message, ticket dans Quoting24
- [ ]
external_iddéjà dansweb_code: association, fiche entreprise inchangée - [ ] Nouveau code avec
company_name: entreprise créée avec ce code web - [ ] Nouveau code sans
company_name: aucune entreprise créée - [ ] E-mail vide, ID numérique ou raison sociale trop longue : payload refusé, à corriger
- [ ] Rechargement et navigation SPA : une seule instance, session invité conservée
- [ ] Changement de compte :
reset()tout de suite, réponses tardives écartées - [ ] Mobile : saisie utilisable
- [ ] Domaine non autorisé : widget refusé
Problèmes fréquents : Résolution des problèmes.