Blu Pantheon
Widget BluBot

Eventi

Eventi emessi dal widget BluBot, payload di ciascuno e inoltro verso Google Analytics 4 e Tag Manager.

BluBot emette eventi in due forme equivalenti: tramite BluBot.on(...) e come CustomEvent su window con il prefisso blubot:. Usa la prima per la logica applicativa, la seconda quando devi ascoltare prima che il widget sia pronto.

Ascolto rapido di tutti gli eventi (debug)

window.BluBot.on('*', (e) => console.log('[blubot]', e))

Incollalo nella console del browser per osservare il flusso degli eventi.

EventoQuando scattaFrequenza
readyIl widget è inizializzato e utilizzabileUna volta per caricamento
openLa finestra di chat viene apertaOgni apertura
closeLa finestra viene chiusaOgni chiusura
message:sentL'utente invia un messaggioOgni messaggio in uscita
message:receivedL'assistente o l'operatore rispondeOgni messaggio in entrata
handover:requestedViene richiesto un operatore umanoUna volta per richiesta
handover:startedUn operatore prende in carico la conversazioneUna volta per presa in carico
booking:completedUna prenotazione viene confermata nel flussoOgni prenotazione
errorSi verifica un errore recuperabile o bloccanteVariabile

ready

Scatta quando il widget ha completato l'inizializzazione, ha validato la chiave di progetto e ha caricato la configurazione. Da questo momento tutti i metodi dell'API sono invocabili.

Payload
{
  "version": "1.24.0",
  "projectKey": "bp_proj_7f3a9c21",
  "sessionId": "ses_c41f7d2a9b0e4386",
  "locale": "it",
  "environment": "production",
  "isReturning": true
}
Ascolto
window.addEventListener('blubot:ready', function (event) {
  console.log('BluBot pronto, sessione', event.detail.sessionId);
  if (event.detail.isReturning) {
    window.BluBot.open();
  }
});

open

Scatta all'apertura della finestra, sia manuale sia programmatica.

Payload
{
  "sessionId": "ses_c41f7d2a9b0e4386",
  "trigger": "launcher",
  "hasUnread": false,
  "timestamp": "2026-09-04T10:15:32.114Z"
}

Valori possibili di trigger: launcher, api, auto_open, proactive_message, deep_link.

Ascolto
window.BluBot.on('open', function (payload) {
  if (payload.trigger === 'auto_open') {
    console.log('Apertura automatica dopo il ritardo configurato');
  }
});

close

Scatta alla chiusura della finestra. La sessione resta attiva.

Payload
{
  "sessionId": "ses_c41f7d2a9b0e4386",
  "trigger": "user",
  "messageCount": 6,
  "durationMs": 184000
}
Ascolto
window.BluBot.on('close', function (payload) {
  if (payload.messageCount === 0) {
    console.log('Chat aperta e chiusa senza interazione');
  }
});

message:sent

Scatta quando l'utente invia un messaggio, anche tramite sendMessage.

Payload
{
  "sessionId": "ses_c41f7d2a9b0e4386",
  "messageId": "msg_a71b90c3",
  "text": "Vorrei prenotare una visita cardiologica",
  "length": 41,
  "hidden": false,
  "timestamp": "2026-09-04T10:16:02.900Z"
}

Contenuto dei messaggi

Il campo text contiene quanto scritto dall'utente e può includere dati personali. Non inoltrarlo a strumenti di analisi: usa length o un valore aggregato.

Ascolto
window.BluBot.on('message:sent', function (payload) {
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push({
    event: 'blubot_message_sent',
    blubot_session_id: payload.sessionId,
    blubot_message_length: payload.length
  });
});

message:received

Scatta a ogni messaggio ricevuto dall'assistente o da un operatore.

Payload
{
  "sessionId": "ses_c41f7d2a9b0e4386",
  "messageId": "msg_a71b90c4",
  "source": "assistant",
  "text": "Certo. Per quale sede preferisci prenotare?",
  "hasWidget": false,
  "citations": [
    { "documentId": "doc_9f31", "title": "Listino prestazioni 2026", "page": 12 }
  ],
  "latencyMs": 1240,
  "timestamp": "2026-09-04T10:16:04.140Z"
}

Valori possibili di source: assistant, operator, system.

Ascolto
window.BluBot.on('message:received', function (payload) {
  if (payload.latencyMs > 5000) {
    console.warn('Risposta lenta:', payload.latencyMs, 'ms');
  }
});

handover:requested

Scatta quando la conversazione viene messa in coda per un operatore umano.

Payload
{
  "sessionId": "ses_c41f7d2a9b0e4386",
  "reason": "user_request",
  "queue": "assistenza-generale",
  "queuePosition": 3,
  "estimatedWaitSec": 120,
  "businessHours": true
}

Valori possibili di reason: user_request, low_confidence, flow_action, repeated_fallback, negative_sentiment, keyword.

Ascolto
window.BluBot.on('handover:requested', function (payload) {
  if (!payload.businessHours) {
    document.getElementById('avviso-orari')?.classList.remove('nascosto');
  }
});

handover:started

Scatta quando un operatore prende in carico la conversazione.

Payload
{
  "sessionId": "ses_c41f7d2a9b0e4386",
  "operator": { "id": "opr_1187", "displayName": "Giulia" },
  "waitedSec": 96,
  "timestamp": "2026-09-04T10:18:04.000Z"
}
Ascolto
window.BluBot.on('handover:started', function (payload) {
  console.log('Presa in carico da', payload.operator.displayName);
});

booking:completed

Scatta quando un flusso conferma una prenotazione. È l'evento da usare per la misurazione delle conversioni.

Payload
{
  "sessionId": "ses_c41f7d2a9b0e4386",
  "bookingId": "bkg_71c9d0a4",
  "service": { "code": "VIS_CARD", "name": "Visita cardiologica" },
  "startsAt": "2026-09-09T09:00:00+02:00",
  "location": { "code": "MI01", "name": "Milano — Vittor Pisani" },
  "value": 120,
  "currency": "EUR",
  "channel": "web"
}
Ascolto
window.BluBot.on('booking:completed', function (payload) {
  window.gtag?.('event', 'purchase', {
    transaction_id: payload.bookingId,
    value: payload.value,
    currency: payload.currency,
    items: [{ item_id: payload.service.code, item_name: payload.service.name }]
  });
});

error

Scatta su ogni errore gestito dal widget.

Payload
{
  "code": "origin_not_allowed",
  "message": "Origin https://www.acme.it is not authorised for this project.",
  "fatal": true,
  "sessionId": null,
  "timestamp": "2026-09-04T10:15:31.002Z"
}
CodiceSignificatofatal
invalid_project_keyChiave inesistente o di un altro ambienteSì
origin_not_allowedDominio non autorizzatoSì
project_archivedProgetto archiviato o sospesoSì
invalid_user_signatureFirma dell'identificativo non validaNo
websocket_failedConnessione in tempo reale non stabilitaNo
rate_limitedTroppi messaggi in poco tempoNo
message_too_longMessaggio oltre 4000 caratteriNo
network_errorErrore di rete transitorioNo
Ascolto
window.BluBot.on('error', function (payload) {
  if (payload.fatal) {
    document.getElementById('contatti-alternativi')?.classList.remove('nascosto');
  }
  window.Sentry?.captureMessage('BluBot: ' + payload.code, { level: 'warning' });
});

Errori non fatali

Con fatal uguale a false il widget continua a funzionare, eventualmente con funzionalità ridotte: ad esempio ripiega sul polling se il WebSocket è bloccato.

Inoltro a Google Analytics 4

Con gtag.js

Inoltro diretto a GA4
<script>
  window.addEventListener('blubot:ready', function () {
    var mapping = {
      open: 'blubot_open',
      close: 'blubot_close',
      'message:sent': 'blubot_message_sent',
      'message:received': 'blubot_message_received',
      'handover:requested': 'blubot_handover_requested',
      'handover:started': 'blubot_handover_started'
    };

    Object.keys(mapping).forEach(function (evt) {
      window.BluBot.on(evt, function (payload) {
        window.gtag('event', mapping[evt], {
          blubot_session_id: payload.sessionId,
          blubot_trigger: payload.trigger || payload.reason || 'n_d'
        });
      });
    });

    window.BluBot.on('booking:completed', function (payload) {
      window.gtag('event', 'generate_lead', {
        currency: payload.currency,
        value: payload.value,
        transaction_id: payload.bookingId
      });
    });
  });
</script>

Con Google Tag Manager

ConsoleGoogle Tag ManagerVariabiliNuova variabile

Pubblica gli eventi sul dataLayer

Crea un tag HTML personalizzato con attivatore Initialization — All Pages.

Tag HTML personalizzato
<script>
  window.dataLayer = window.dataLayer || [];
  window.addEventListener('blubot:ready', function () {
    ['open', 'close', 'message:sent', 'handover:requested', 'booking:completed'].forEach(
      function (evt) {
        window.BluBot.on(evt, function (payload) {
          window.dataLayer.push({
            event: 'blubot_' + evt.replace(':', '_'),
            blubot_session_id: payload.sessionId || null,
            blubot_value: payload.value || null,
            blubot_currency: payload.currency || null,
            blubot_reason: payload.reason || payload.trigger || null
          });
        });
      }
    );
  });
</script>

Crea le variabili del dataLayer

Crea una variabile di tipo Variabile livello dati per ciascuna chiave: blubot_session_id, blubot_value, blubot_currency, blubot_reason.

Crea gli attivatori

Attivatore di tipo Evento personalizzato per ogni nome, ad esempio blubot_booking_completed.

Collega il tag GA4

Crea un tag GA4 — Evento che usa gli attivatori e passa le variabili come parametri dell'evento.

Verifica e pubblica

Usa Anteprima, esegui una conversazione di prova e controlla il DebugView di GA4. Poi pubblica il contenitore.

Non inviare il testo dei messaggi

Inoltrare payload.text a Google Analytics costituisce un trasferimento di dati personali non necessario e viola le condizioni d'uso del servizio. Invia solo identificativi e metriche aggregate. Vedi Conformità.

Eventi come CustomEvent

Ogni evento è disponibile anche su window con prefisso blubot: e payload in event.detail. Questa forma funziona anche prima che il widget sia pronto.

Equivalenza tra le due forme
window.BluBot.on('booking:completed', function (payload) { /* ... */ });

window.addEventListener('blubot:booking:completed', function (event) {
  var payload = event.detail;
});

Passi successivi

Sur cette page