Skip to content

Instantly share code, notes, and snippets.

@pacotole
Created March 24, 2026 14:15
Show Gist options
  • Select an option

  • Save pacotole/6a04214c4d76e71539abb0fbe4c91800 to your computer and use it in GitHub Desktop.

Select an option

Save pacotole/6a04214c4d76e71539abb0fbe4c91800 to your computer and use it in GitHub Desktop.
Joinchat Chat Funnels - JavaScript Custom Events Docs

📡 Joinchat Chat Funnels - Custom Events

Documentación completa de todos los eventos personalizados (Custom Events) que dispara Joinchat Chat Funnels.


📋 Índice

  1. Eventos de ciclo de vida
  2. Eventos de interacción
  3. Eventos de datos
  4. Eventos de acciones
  5. Eventos de sistema
  6. Guía de uso
  7. Ejemplos prácticos

🔄 Eventos de ciclo de vida

joinchat:start

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

joinchat:show

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

joinchat:agents

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

💬 Eventos de interacción

joinchat:bubble

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

joinchat:input

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

joinchat:contact

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

📊 Eventos de datos

joinchat:webhookSuccess

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 capturado
  • phone: Teléfono capturado
  • nombre, 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'
  });
});

joinchat:webhookError

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

joinchat:submitSuccess

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

joinchat:submitError

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

⚙️ Eventos de acciones

joinchat:funnel

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

joinchat:qr

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

joinchat:ai

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

🔧 Eventos de sistema

Información adicional

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.


📖 Guía de uso

Sintaxis básica

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

Mejores prácticas

  1. Usar document como objetivo: La mayoría de eventos se disparan en document, excepto joinchat:bubble que se dispara en .joinchat__chat.

  2. 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);
  }
});
  1. 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);
});
  1. 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);

💡 Ejemplos prácticos

Ejemplo 1: Tracking completo del funnel

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

Ejemplo 2: Guardar leads en localStorage

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

Ejemplo 3: Enviar conversión solo en mensaje específico

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

Ejemplo 4: Cambiar de funnel según página

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

Ejemplo 5: Manejo completo de errores

// 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.');
});

Ejemplo 6: Combo completo - GA4 + Enhanced Conversions

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

📚 Resumen de eventos

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

🔗 Referencias


❓ FAQ

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment