Documentación completa de todos los eventos personalizados (Custom Events) que dispara Joinchat Chat Funnels.
- Eventos de ciclo de vida
- Eventos de interacción
- Eventos de datos
- Eventos de acciones
- Eventos de sistema
- Guía de uso
- Ejemplos prácticos
Se dispara: Cuando Joinchat se inicializa en la página.
Objetivo: document
Detail: No tiene detail
Uso típico: Inicialización de funcionalidades adicionales, configuraciones iniciales.
document.addEventListener('joinchat:start', function(e) {
console.log('Joinchat iniciado');
// Tu código de inicialización
});Se dispara: Cuando el chatbox de Joinchat se muestra al usuario.
Objetivo: document
Detail: Puede contener información del evento que lo disparó
Uso típico: Tracking de visualizaciones, iniciar funnels automáticamente.
document.addEventListener('joinchat:show', function(e) {
console.log('Chatbox mostrado');
gtag('event', 'chat_opened');
});Se dispara: Cuando cambia el estado de los agentes (online/offline) en Support Agents addon.
Objetivo: document
Detail: Información sobre el estado de los agentes
Uso típico: Cargar funnels diferentes según disponibilidad de agentes.
document.addEventListener('joinchat:agents', function(e) {
console.log('Estado de agentes actualizado');
});Se dispara: Cada vez que se muestra un mensaje (burbuja) en el chat.
Objetivo: .joinchat__chat (elemento del chat)
Detail:
{
bubble: HTMLElement, // El elemento DOM de la burbuja
message: String // El contenido HTML del mensaje
}Uso típico: Ejecutar acciones en mensajes específicos, analytics, animaciones.
// En el elemento .joinchat__chat
document.querySelector('.joinchat__chat').addEventListener('joinchat:bubble', function(e) {
console.log('Mensaje mostrado:', e.detail.message);
// Ejecutar algo cuando aparece un mensaje concreto
if (e.detail.message.includes('¡Gracias!')) {
console.log('Mensaje de agradecimiento mostrado');
}
});
// Alternativa: escuchar en document
document.addEventListener('joinchat:bubble', function(e) {
// También funciona si el evento burbujea
});Se dispara: Cada vez que el usuario completa un campo de entrada (input).
Objetivo: document
Detail:
{
name: String, // Nombre del campo (ej: "email", "nombre")
value: String, // Valor ingresado por el usuario
input: String // Tipo de input: "email", "phone", "text", "number", "date", "time", "select"
}Uso típico: Captura de datos en tiempo real, validaciones personalizadas, tracking.
document.addEventListener('joinchat:input', function(e) {
console.log(`Campo ${e.detail.name} completado:`, e.detail.value);
// Capturar email específicamente
if (e.detail.input === 'email') {
console.log('Email capturado:', e.detail.value);
window.userEmail = e.detail.value;
}
// Capturar teléfono
if (e.detail.input === 'phone') {
console.log('Teléfono capturado:', e.detail.value);
}
// Capturar selección de opciones
if (e.detail.input === 'select') {
console.log('Opción seleccionada:', e.detail.value);
}
});Se dispara: Cuando se habilitan las opciones de contacto (botón de WhatsApp).
Objetivo: document
Detail: No tiene detail
Uso típico: Actualizar QR codes, habilitar botones personalizados.
document.addEventListener('joinchat:contact', function(e) {
console.log('Opciones de contacto habilitadas');
// Actualizar UI personalizada
});Se dispara: Cuando un webhook se completa exitosamente.
Objetivo: document
Detail:
{
payload: Object, // Datos enviados al webhook
response: Mixed // Respuesta del servidor (JSON o texto)
}Campos típicos en payload:
email: Email capturadophone: Teléfono capturadonombre,name: Nombre del usuario- Cualquier campo personalizado configurado en el funnel
- Metadatos:
url,title,utm_*,date,time, etc.
Uso típico: Enviar conversiones, guardar en analytics, sincronizar con CRM.
document.addEventListener('joinchat:webhookSuccess', function(e) {
console.log('Webhook exitoso');
console.log('Datos enviados:', e.detail.payload);
console.log('Respuesta:', e.detail.response);
// Enviar a Google Analytics
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'lead_captured',
'email': e.detail.payload.email,
'source': 'joinchat_funnel'
});
});Se dispara: Cuando un webhook falla.
Objetivo: document
Detail:
{
payload: Object, // Datos que se intentaron enviar
error: Error // Objeto de error con detalles del fallo
}Uso típico: Logging de errores, reintentos, notificaciones.
document.addEventListener('joinchat:webhookError', function(e) {
console.error('Error en webhook:', e.detail.error);
console.log('Datos que fallaron:', e.detail.payload);
// Enviar error a tracking
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'webhook_error',
'error_message': e.detail.error.message
});
// Guardar en localStorage para reintentar
localStorage.setItem('failed_lead', JSON.stringify(e.detail.payload));
});Se dispara: Cuando un formulario se envía exitosamente al servidor (action: submit).
Objetivo: document
Detail:
{
data: Object, // Datos de la submission
response: Mixed // Respuesta del servidor
}Uso típico: Confirmación de envío, conversiones, redirecciones.
document.addEventListener('joinchat:submitSuccess', function(e) {
console.log('Formulario enviado con éxito');
console.log('Datos enviados:', e.detail.data);
// Redirigir a página de gracias
// window.location.href = '/gracias';
});Se dispara: Cuando falla el envío al servidor.
Objetivo: document
Detail:
{
data: Object, // Datos que se intentaron enviar
error: Error // Error del envío
}Uso típico: Manejo de errores, reintentos.
document.addEventListener('joinchat:submitError', function(e) {
console.error('Error al enviar:', e.detail.error);
alert('Hubo un error. Por favor, intenta nuevamente.');
});Se dispara: Programáticamente para cargar un funnel específico.
Objetivo: document
Detail (para disparar):
{
funnel: Number, // ID del funnel a cargar
start_at: Number, // (Opcional) Paso por el que empezar (default: 0)
reset: Boolean // (Opcional) Resetear inputs previos (default: false)
}Uso típico: Cambiar de funnel dinámicamente según condiciones.
// Disparar el evento para cargar un funnel
document.dispatchEvent(new CustomEvent('joinchat:funnel', {
detail: {
funnel: 2, // ID del funnel
start_at: 0, // Empezar desde el primer paso
reset: true // Resetear datos previos
}
}));
// Escuchar el evento (opcional)
document.addEventListener('joinchat:funnel', function(e) {
console.log('Cargando funnel:', e.detail.funnel);
});Se dispara: Para actualizar códigos QR cuando cambia el teléfono o mensaje.
Objetivo: document
Detail:
{
id: String, // ID del teléfono/agente
message: String // Mensaje personalizado
}Uso típico: Actualización de QR codes en multiple agents.
document.addEventListener('joinchat:qr', function(e) {
console.log('Actualizando QR para:', e.detail.id);
// Código de actualización de QR
});Se dispara: Cuando se activa una opción de IA (AI Assistant integration).
Objetivo: document
Detail:
{
chat: Array, // Historial de mensajes del chat
inputs: Object, // Inputs capturados hasta el momento
metas: Object // Metadatos (url, title, utm_*, etc.)
}Uso típico: Integración con IA, análisis de conversación.
document.addEventListener('joinchat:ai', function(e) {
console.log('Activando IA');
console.log('Historial chat:', e.detail.chat);
console.log('Inputs capturados:', e.detail.inputs);
console.log('Metadatos:', e.detail.metas);
// Enviar a tu sistema de IA
// sendToAI(e.detail);
});Algunos eventos no están documentados aquí porque son internos o experimentales. Los eventos listados arriba son los públicos y estables para uso en producción.
// Escuchar un evento
document.addEventListener('joinchat:nombreEvento', function(event) {
console.log('Evento disparado:', event.detail);
});
// Disparar un evento (solo para eventos que lo permiten)
document.dispatchEvent(new CustomEvent('joinchat:nombreEvento', {
detail: {
// tus datos aquí
}
}));-
Usar
documentcomo objetivo: La mayoría de eventos se disparan endocument, exceptojoinchat:bubbleque se dispara en.joinchat__chat. -
Verificar disponibilidad de datos:
document.addEventListener('joinchat:webhookSuccess', function(e) {
if (e.detail && e.detail.payload && e.detail.payload.email) {
// Safe to use email
console.log(e.detail.payload.email);
}
});- Evitar bloqueos: No ejecutes código pesado en los listeners:
document.addEventListener('joinchat:input', function(e) {
// ❌ Malo: operación síncrona pesada
// processHeavyTask(e.detail.value);
// ✅ Bueno: usar timeout o async
setTimeout(() => processHeavyTask(e.detail.value), 0);
});- Limpiar listeners si es necesario:
function handleWebhook(e) {
console.log('Webhook recibido');
}
// Agregar listener
document.addEventListener('joinchat:webhookSuccess', handleWebhook);
// Remover listener si es necesario
document.removeEventListener('joinchat:webhookSuccess', handleWebhook);// Inicialización
document.addEventListener('joinchat:start', function() {
console.log('Joinchat iniciado');
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ 'event': 'joinchat_ready' });
});
// Chat abierto
document.addEventListener('joinchat:show', function() {
window.dataLayer.push({ 'event': 'joinchat_opened' });
});
// Inputs capturados
document.addEventListener('joinchat:input', function(e) {
window.dataLayer.push({
'event': 'joinchat_input',
'field_type': e.detail.input,
'field_name': e.detail.name
});
});
// Lead capturado
document.addEventListener('joinchat:webhookSuccess', function(e) {
window.dataLayer.push({
'event': 'lead_captured',
'lead_email': e.detail.payload.email,
'lead_source': 'joinchat_funnel'
});
});document.addEventListener('joinchat:webhookSuccess', function(e) {
const lead = {
...e.detail.payload,
timestamp: Date.now(),
page_url: window.location.href
};
// Guardar en localStorage
const leads = JSON.parse(localStorage.getItem('joinchat_leads') || '[]');
leads.push(lead);
localStorage.setItem('joinchat_leads', JSON.stringify(leads));
console.log('Lead guardado localmente:', lead);
});// Solo enviar conversión cuando aparece el mensaje de confirmación
document.querySelector('.joinchat__chat')?.addEventListener('joinchat:bubble', function(e) {
if (e.detail.message.includes('¡Registro completado!')) {
gtag('event', 'conversion', {
'send_to': 'AW-XXXXXXXXX/YYYYYYY'
});
console.log('Conversión enviada');
}
});document.addEventListener('joinchat:show', function() {
// Cargar funnel diferente según la página
const path = window.location.pathname;
if (path.includes('/productos/')) {
// Funnel de productos
document.dispatchEvent(new CustomEvent('joinchat:funnel', {
detail: { funnel: 2, reset: true }
}));
} else if (path.includes('/blog/')) {
// Funnel de blog
document.dispatchEvent(new CustomEvent('joinchat:funnel', {
detail: { funnel: 3, reset: true }
}));
}
});// Capturar errores de webhook
document.addEventListener('joinchat:webhookError', function(e) {
console.error('Webhook falló:', e.detail.error);
// Guardar para reintentar
const failedData = {
payload: e.detail.payload,
timestamp: Date.now(),
error: e.detail.error.message
};
localStorage.setItem('failed_webhook', JSON.stringify(failedData));
// Notificar al usuario (opcional)
console.warn('Los datos se guardarán localmente para reenviar');
});
// Capturar errores de submit
document.addEventListener('joinchat:submitError', function(e) {
console.error('Submit falló:', e.detail.error);
alert('Hubo un error al enviar. Por favor, intenta nuevamente.');
});let userData = {};
// Capturar inputs
document.addEventListener('joinchat:input', function(e) {
userData[e.detail.name] = e.detail.value;
});
// Webhook exitoso: enviar todo
document.addEventListener('joinchat:webhookSuccess', async function(e) {
const data = e.detail.payload;
// 1. GA4 - generate_lead
gtag('event', 'generate_lead', {
'currency': 'EUR',
'value': 10.00
});
// 2. DataLayer
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'lead_captured',
'email': data.email,
'phone': data.phone,
'timestamp': new Date().toISOString()
});
// 3. Enhanced Conversion (hasheado)
if (data.email) {
async function hash(str) {
const buf = await crypto.subtle.digest('SHA-256',
new TextEncoder().encode(str.toLowerCase().trim()));
return Array.from(new Uint8Array(buf))
.map(b => b.toString(16).padStart(2, '0')).join('');
}
gtag('event', 'conversion', {
'send_to': 'AW-XXXXXXXXX/YYYYYYYY',
'user_data': {
'sha256_email_address': await hash(data.email),
'sha256_phone_number': data.phone ? await hash(data.phone) : undefined
}
});
}
console.log('✅ Todo enviado: GA4 + dataLayer + Enhanced Conversion');
});| Evento | Cuándo se dispara | Detail disponible | Objetivo |
|---|---|---|---|
joinchat:start |
Joinchat se inicia | No | document |
joinchat:show |
Chatbox mostrado | Varía | document |
joinchat:agents |
Cambio estado agentes | Varía | document |
joinchat:bubble |
Mensaje mostrado | bubble, message |
.joinchat__chat |
joinchat:input |
Usuario completa campo | name, value, input |
document |
joinchat:contact |
Contacto habilitado | No | document |
joinchat:webhookSuccess |
Webhook exitoso | payload, response |
document |
joinchat:webhookError |
Webhook falló | payload, error |
document |
joinchat:submitSuccess |
Submit exitoso | data, response |
document |
joinchat:submitError |
Submit falló | data, error |
document |
joinchat:funnel |
Cargar funnel | funnel, start_at, reset |
document |
joinchat:qr |
Actualizar QR | id, message |
document |
joinchat:ai |
Activar IA | chat, inputs, metas |
document |
- Ejemplos de webhooks - 10 ejemplos completos
- Cheat sheet webhooks - Referencia rápida
- README Webhooks - Guía de integración
- Enhanced Conversions - Implementación completa
P: ¿Puedo modificar el detail de un evento?
R: No, el detail es de solo lectura. Puedes copiar los datos y trabajar con ellos.
P: ¿Los eventos se disparan si el chatbox está cerrado?
R: Algunos sí (como joinchat:start), otros solo cuando está abierto.
P: ¿Puedo cancelar un evento?
R: No, estos eventos son informativos y no se pueden cancelar con preventDefault().
P: ¿Cuál es la diferencia entre webhookSuccess y submitSuccess?
R: webhookSuccess es para webhooks externos. submitSuccess es para envíos al servidor de WordPress.
P: ¿Los eventos burbujean (bubble)?
R: Sí, la mayoría burbujean hasta document, por eso se recomienda escuchar ahí.
Última actualización: Marzo 2026 Versión: 1.0 Compatibilidad: Joinchat Premium Chat Funnels addon