Widget B2C — visitatore ospite e azienda
Questa sezione copre le integrazioni in cui il widget resta in sessione ospite:
- sito pubblico, visitatore sconosciuto: solo lo script e il modulo di contatto
- sito o portale che conosce già l’account:
init()con profilo e dati azienda, modulo saltato quando i dati bastano, contatto collegato all’azienda
La cronologia personale su un altro browser o dispositivo è un’altra integrazione. Vedi Widget B2B. Contratto completo dei campi, cambio account in una SPA, CSP e provisioning: Integrazione tecnica.
Associare un’azienda non autorizza la cronologia di un’altra persona. Anche un utente autenticato nel sito resta un ospite del widget finché non invii external_user_id insieme a un restore_id valido.
Cosa ottieni
- Pulsante flottante, oppure chat incorporata in un contenitore della pagina
- Modulo iniziale per chi è sconosciuto: etichette Telefono e Nome. In
init()i campi sonophoneename - Sessione ospite salvata dal loader nello stesso browser, separata per chiave widget. Se il
localStorageè bloccato, la continuità può restare sulla pagina corrente - Se invii
external_id, Quoting24 cerca un’azienda con lo stessoweb_code. Con anchecompany_name, può creare l’azienda mancante e collegarvi il contatto - Ticket e risposte in Quoting24, come sugli altri canali
La sessione ospite rilegge la propria conversazione più recente anche dopo la chiusura della scheda. Non segue la persona su un altro browser.
1. Prerequisiti in Quoting24
- Canale Widget attivo in Impostazioni → Canali
- Logo, colore, posizione, saluto, benvenuto e fuori orario configurati
- Domini consentiti aggiornati, compresi collaudo e
localhost - Codice embed copiato dalla configurazione del canale: URL dello script e chiave pubblica
Usa host e chiave dello stesso ambiente. Negli esempi sostituisci HOST_WIDGET e CHIAVE_PUBBLICA_WIDGET.
I domini sono nomi host, senza https://, porta, percorso o *.. example.com include i sottodomini. Lista vuota: nessuna restrizione. In locale servi la pagina via HTTP, non come file://.
Il company_name di init() è la ragione sociale del cliente. Non è il titolo del widget e non si configura da questo payload.
2. Installare il pulsante flottante
Incolla lo script una sola volta, prima di </body>:
<script
src="https://HOST_WIDGET/assets/widget/script.js?key=CHIAVE_PUBBLICA_WIDGET"
async
></script>
Il pulsante compare dopo il caricamento delle impostazioni grafiche. Un nuovo visitatore vede il modulo di contatto. Chi torna sullo stesso browser riprende la sessione ospite, se lo storage è disponibile.
Lo script espone un unico window.Quoting24Widget.
3. Incorporare la chat in pagina
Crea il contenitore prima dello script e assegnagli un’altezza esplicita:
<section aria-labelledby="titolo-assistenza">
<h2 id="titolo-assistenza">Assistenza</h2>
<div id="chat-assistenza" style="width: 100%; height: 600px;"></div>
</section>
<script
src="https://HOST_WIDGET/assets/widget/script.js?key=CHIAVE_PUBBLICA_WIDGET&mode=embedded&target=chat-assistenza"
async
></script>
targetè l’ID dell’elemento, senza#- L’iframe riempie il contenitore
- Non c’è pulsante flottante
open(),close()etoggle()non hanno effetto- Su questa modalità il sito decide altezza e larghezza. In modalità flottante, su mobile, la chat può occupare il viewport
La modalità incorporata, da sola, non abilita il ripristino della cronologia.
4. Inviare il profilo del cliente
Quando il sito conosce l’account, invia il profilo dopo il caricamento del loader. I campi sono stringhe. Ometti quelli sconosciuti: non inviare null, ID numerici o un’email vuota.
window.Quoting24Widget.init({
external_id: "52",
company_name: "Ricambi Stella S.r.l.",
name: "mario.rossi",
phone: "+393331234567",
email: "amministrazione@ricambi-stella.example",
});
| Dato nel sito o nel gestionale | Campo | Significato |
|---|---|---|
Riferimento stabile dell’azienda, lo stesso valore importato in web_code |
external_id |
Confronto esatto con companies.web_code, nell’organizzazione del widget |
| Ragione sociale | company_name |
Usata se l’azienda va creata |
| Nome della persona o dell’utente | name |
Nome mostrato sul contatto |
| Email dell’account | email |
Salvata sull’azienda solo quando l’azienda viene creata |
| Telefono, se lo conosci | phone |
Numero del contatto. Preferisci il formato internazionale, per esempio +393331234567 |
Questo payload non invia external_user_id né restore_id. Mantieni separati name e company_name: non concatenare la ragione sociale al nome utente per ottenere l’associazione. Il campo pubblico è external_id. Non inviare web_code, l’UUID interno di Quoting24 o companies.code.
Il modulo mostra Nome e Telefono. In init() i campi si chiamano name e phone. L’email si chiama email. Nome, Telefono ed Email non sono chiavi: il loader le scarta, come scarta web_code al posto di external_id.
Esempi
Nome e telefono, gli stessi dati del modulo. La chat parte e non cerca un’azienda.
Profilo con azienda. name è la persona, phone il numero del contatto, email l’indirizzo scritto sull’azienda solo se questa chiamata la crea.
widget.init({
external_id: "52",
company_name: "Ricambi Stella S.r.l.",
name: "Mario Rossi",
phone: "+393331234567",
email: "mario.rossi@ricambi-stella.example",
});
Solo email. Un indirizzo valido in email basta per aprire la sessione.
Se un campo supera i limiti o l’email è malformata, la richiesta viene rifiutata. Limiti e comportamento di ogni campo: Integrazione tecnica.
Attendere il loader
Uno script async può non essere ancora eseguito quando il codice successivo chiama init(). Per i dati precompilati usa un modulo di caricamento al posto del tag statico, importato una sola volta nel layout principale:
// /assets/quoting24-loader.js
const widgetScriptUrl =
"https://HOST_WIDGET/assets/widget/script.js?key=CHIAVE_PUBBLICA_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 del widget non disponibile"));
}
};
script.onerror = () => {
script.remove();
reject(new Error("Caricamento del widget non riuscito"));
};
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",
});
Importa il modulo dal bundler, oppure carica il file di ingresso con <script type="module" src="/assets/assistenza.js"></script>. Per la modalità incorporata aggiungi &mode=embedded&target=chat-assistenza all’URL e monta prima il contenitore.
loadWidget() segnala solo che l’API JavaScript è disponibile. init() restituisce void: accoda il profilo se l’iframe non è pronto e non attende la sessione. Per l’esito usa isReady() e hasSessionError().
init() sostituisce il profilo memorizzato, non lo unisce al precedente. Passa tutti i campi che devono restare.
Un cambio di pagina in una SPA non richiede un nuovo script né un reset(). Al cambio di persona o account, e al logout, chiama reset() prima del nuovo profilo: cambiare solo i campi non stacca la sessione ospite precedente. Pattern completo: Login, logout e cambio account.
5. Come viene associata o creata l’azienda
Quoting24 esegue questo flusso all’inizializzazione, anche se il visitatore non ha ancora inviato un messaggio:
- Con un
external_idnon vuoto, cerca un’azienda della stessa organizzazione conweb_codeuguale a quel valore - Se la trova, collega il contatto. Nome ed email dell’azienda esistente restano invariati
- Se non la trova e c’è anche un
company_namenon vuoto, crea l’azienda conname = company_name,web_code = external_ided eventualeemail, poi collega il contatto - Se non può trovare o creare l’azienda, prosegue con il profilo disponibile. Se per un nuovo ospite non basta, mostra il modulo. Errori di database o il limite di richieste fanno fallire l’inizializzazione
| Dati inviati | Situazione in Quoting24 | Risultato |
|---|---|---|
external_id: "52", company_name: "Ricambi Stella S.r.l." |
Esiste web_code = "52" |
Usa l’azienda esistente e non ne modifica il nome |
| Stessi dati, più un’email valida | Non esiste web_code = "52" |
Crea l’azienda con codice web 52, ragione sociale ed email, e associa il contatto |
external_id: "52", name: "mario.rossi" |
Nessuna corrispondenza | Avvia l’ospite senza una nuova associazione aziendale |
external_id: "52", senza altri dati |
Esiste una corrispondenza | Avvia l’ospite associato all’azienda, con nome di default Visitatore |
external_id: "52", senza altri dati |
Nessuna corrispondenza | Mostra il modulo di contatto |
company_name senza external_id, più name |
Qualsiasi | Avvia il visitatore. Non cerca e non crea un’azienda |
La ricerca non usa ragione sociale, email, telefono, partita IVA o companies.code. "052" e "52" sono valori diversi; gli spazi in external_id non vengono tolti. Se importi l’anagrafica prima, scrivi in web_code lo stesso valore che il sito invierà in external_id. Vedi anche Aziende → Codice web.
Un nuovo ospite parte se c’è almeno un nome, un telefono, un’email valida o un external_user_id, oppure un’azienda trovata o creata tramite external_id. init({}) e company_name da solo non avviano una sessione.
Per un contatto già collegato, un nuovo codice valido può cambiarne l’azienda. Omettere il codice, o inviarne uno non risolto, non cancella l’associazione precedente. Al cambio persona o account serve reset().
Limiti
web_code non è univoco. Con più corrispondenze, l’inizializzazione pubblica prende la prima in ordine di data di creazione crescente. Richieste simultanee che non trovano ancora l’azienda possono crearne più di una: la creazione non è atomica e non sostituisce un import o una sincronizzazione dal gestionale.
La creazione implicita è limitata a 20 tentativi per finestra di 60 secondi e indirizzo IP, nel processo backend che gestisce la richiesta. Oltre il limite l’inizializzazione fallisce con TOO_MANY_REQUESTS: riprova con attesa, senza cicli continui di init().
I dati partono dal browser e il visitatore può alterarli. Il collegamento non prova l’appartenenza all’azienda e non concede la cronologia aziendale. Invia company_name solo se vuoi consentire questa creazione pubblica. Per aggiornare aziende già presenti usa gli strumenti di Quoting24 o un’integrazione gestionale autorizzata.
L’email dell’inizializzazione pubblica finisce solo sull’azienda nuova. Non viene scritta sul contatto e non aggiorna un’azienda già presente. Un telefono già usato da un altro contatto non unisce contatti o chat.
6. Comportamento sul sito
| Situazione | Comportamento atteso |
|---|---|
| Primo visitatore, solo script | Pulsante, poi modulo, poi chat |
init() con profilo sufficiente |
Modulo saltato |
external_id già presente come web_code |
Contatto associato; nome ed email dell’azienda invariati |
external_id nuovo con company_name |
Azienda creata e contatto associato |
Codice nuovo e nome, senza company_name |
Chat senza nuova azienda |
| Solo codice nuovo | Modulo di contatto |
| Solo ragione sociale e nome | Nessuna ricerca o creazione per nome |
| Ricarica nello stesso browser | Sessione ospite ripresa, se lo storage è disponibile |
| Altro browser o dispositivo | Nuova sessione ospite |
| Fuori orario | Banner fuori orario; la composizione resta utilizzabile |
| Mobile, pulsante flottante | La chat può occupare il viewport |
Allegati: PDF, DOC, DOCX, JPG/JPEG, PNG. Massimo 10 MiB per file e 100 MiB di allegati referenziati per conversazione.
7. Controlli utili
Quando il pulsante flottante è visibile puoi collegare un pulsante del sito a window.Quoting24Widget?.open().
| Metodo | Uso |
|---|---|
init(profile) |
Imposta o sostituisce il profilo corrente |
open() / close() / toggle() |
Solo widget flottante. Chiudere non è un logout |
isReady() |
Sessione visitatore avviata. Resta falso sul modulo di contatto |
hasSessionError() |
Errore di sessione segnalato dall’iframe |
reset() |
Cancella profilo, sessione locale, credenziale ospite salvata e non letti di questa istanza |
dispose() |
Smonta interfaccia e listener. Non cancella la credenziale ospite salvata né l’oggetto API globale |
Non aspettare isReady() per far aprire il modulo a un nuovo ospite. Non c’è un evento pubblico di disponibilità. Questi indicatori non descrivono tutto lo stato di rete.
Checklist prima del rilascio
- [ ] Host e chiave dello stesso ambiente
- [ ] Domini del sito e dello staging in elenco, solo come hostname
- [ ] Logo, colore, saluto, benvenuto e fuori orario verificati
- [ ] Browser nuovo, solo script: modulo, messaggio, ticket in Quoting24
- [ ]
external_idgià inweb_code: associazione, anagrafica azienda invariata - [ ] Codice nuovo con
company_name: azienda creata con quel codice web - [ ] Codice nuovo senza
company_name: nessuna azienda creata - [ ] Email vuota, ID numerico o ragione sociale troppo lunga: payload rifiutato, da correggere
- [ ] Ricarica e navigazione SPA: una sola istanza, sessione ospite conservata
- [ ] Cambio account:
reset()subito, risposte tardive scartate - [ ] Mobile: composizione utilizzabile
- [ ] Dominio non autorizzato: widget rifiutato
Problemi frequenti: Risoluzione dei problemi.