HelpStackDocs

Integraciones

Inserción del widget

Inserte el widget de chat web de HelpStack en cualquier sitio web con una única etiqueta de script.

Datos rápidos#

Loaderhttps://helpstack.eu/widget.js
AutenticaciónNinguna — los endpoints del widget son públicos
TransporteSocket.IO (principal) + fallback REST
Tipo de canalWEBSITE_CHAT
Límite de tasa~30 req/min/IP en config/FAQ/status; ~20 msg/min/visitante en el fallback HTTP de mensajes
Control de origenLista de dominios permitidos opcional por canal (403 si no está permitido)

El loader obtiene su baseUrl de su propio origen <script src>, por lo que el widget.js servido desde helpstack.eu se comunica automáticamente con HelpStack — no hay nada más que configurar.

Fragmento de inserción#

<script src="https://helpstack.eu/widget.js?id=CHANNEL_ID" async></script>

CHANNEL_ID es el id de su canal WEBSITE_CHAT. El loader se inicializa automáticamente desde el parámetro de consulta ?id= — no se requiere JavaScript adicional.

Cómo obtener el CHANNEL_ID#

En el panel de control, vaya a Settings → Channels, abra (o cree) un canal Website Chat y copie su id usando el botón de copia que aparece junto al canal. Ese id es el que se pasa como ?id=CHANNEL_ID.

Cómo funciona el loader#

  1. El script lee su propio <script src> para determinar:
    • baseUrl — el origen del script (p. ej. https://helpstack.eu)
    • channelId — el parámetro de consulta ?id=
  2. Inyecta una burbuja de chat flotante y un <iframe> que apunta a:
    {baseUrl}/widget/{channelId}?visitorId={visitorId}
    
  3. El iframe abre una conexión Socket.IO para mensajería en tiempo real, con un fallback HTTP cuando WebSocket no está disponible.

Identidad del visitante#

El loader genera un id de visitante persistente almacenado en localStorage:

ClaveFormato del valor
chat_widget_visitor_idvisitor_<uuid>

El mismo visitorId se reutiliza en cargas de página y sesiones en ese navegador, de modo que un visitante que regresa se reconecta a su conversación existente. Limpiar localStorage (o usar un navegador/dispositivo diferente) genera un nuevo visitante y un nuevo hilo de conversación.

API programática#

El loader expone un objeto global window.ChatWidget:

window.ChatWidget.init('CHANNEL_ID'); // inicializar manualmente (si no se usa ?id=)
window.ChatWidget.open();             // abrir el panel de chat
window.ChatWidget.close();            // cerrar el panel de chat
window.ChatWidget.toggle();           // alternar entre abierto/cerrado

También está disponible un asistente de cola de comandos para la forma diferida usada en el comentario del fragmento:

window.chat('init', 'CHANNEL_ID');

Identifique en cualquier momento con quién está hablando, para que la IA no tenga que preguntarlo:

window.ChatWidget.identify({ name: 'Ana Novak', email: 'ana@example.com' },
                           { plan: 'pro', account_id: '1234' });

Registre una agent tool del lado del cliente para que la IA pueda llamar a código que se ejecuta en su página:

window.HelpStack('registerTool', 'highlight', async ({ section }) => {
  document.querySelector(`#${section}`)?.scrollIntoView({ behavior: 'smooth' });
  return { highlighted: section };
});

Lo que devuelva el handler es lo que lee la IA. Por debajo, el iframe del widget envía TOOL_EXECUTE por postMessage a la ventana padre y espera un TOOL_RESULT o TOOL_ERROR con el mismo callId; registerTool responde eso por usted. El widget guarda silencio ante cualquier nombre de herramienta para el que no tenga handler, así que un message listener propio que ya tuviera sigue funcionando. Consulte Herramientas de agente personalizadas.

Configuración de apariencia#

La apariencia se configura en el panel de control o por MCP (get_widget_config / update_widget_config, véase MCP), no mediante el fragmento de inserción. El widget la obtiene del servidor (GET /api/widget/[channelId]/config) y la aplica mediante variables CSS. Campos configurables verificados:

CampoNotas
primaryColorColor hexadecimal. Por defecto #247f7c (el turquesa de la marca)
positionbottom-right | bottom-left | top-right | top-left
mobilePositionMismo enum que position, aplicado en viewports móviles
bubbleIconTypecustom o un preset
bubbleIconNameUno de: message, help, smile, headphone, zap, heart
bubbleOffsetXDesplazamiento horizontal de la burbuja
bubbleOffsetYDesplazamiento vertical de la burbuja
greetingMessageTexto de saludo que se muestra cuando se abre el panel
avatarUrlAvatar del agente/marca
showOnlineStatusSi se muestra el estado en línea/fuera de línea
offlineMessageMensaje que se muestra cuando el canal está fuera de línea
productCardsMostrar los enlaces a productos de las respuestas como tarjetas. Por defecto true. Ver Tarjetas de producto

Endpoints públicos del widget#

Todos los endpoints son públicos (sin autenticación) y están limitados por IP/visitante.

MétodoRutaPropósito
GET/api/widget/[channelId]/configConfiguración del widget (colores, posición, saludo, avatar, estado). ~30 req/min/IP
GET/api/widget/[channelId]/faqsHasta 5 chips de FAQ para el saludo. ~30 req/min/IP
GET/api/widget/[channelId]/statusSi el canal está actualmente en línea
POST/api/widget/[channelId]/uploadSubida de archivos multipart/form-data
POST/api/widget/messageFallback HTTP para enviar un mensaje cuando WebSocket no está disponible. ~20 msg/min/visitante

Respuesta de subida (POST /api/widget/[channelId]/upload):

{
  "storagePath": "...",
  "publicUrl": "...",
  "fileName": "...",
  "fileSize": 12345,
  "contentType": "image/png",
  "width": 800,
  "height": 600
}

width y height solo están presentes para imágenes.

Fallback de mensajes (POST /api/widget/message) — cuerpo:

{
  "channelId": "CHANNEL_ID",
  "visitorId": "visitor_<uuid>",
  "content": "Hello, I need help",
  "visitorInfo": {
    "userAgent": "...",
    "currentUrl": "https://example.com/pricing",
    "referrer": "https://google.com"
  }
}

visitorInfo es opcional, igual que metadata (el mismo envoltorio opcional que acepta el evento join del socket). El canal debe ser de tipo WEBSITE_CHAT o la solicitud se rechaza. En caso de éxito, el campo data del envoltorio de respuesta contiene { messageId, conversationId, createdAt }. La conversación de un visitante se crea con su primer mensaje, así que la primera llamada correcta es la que hace que exista conversationId; las llamadas posteriores del mismo visitante la reutilizan.

Eventos en tiempo real (Socket.IO)#

El iframe se comunica con el servidor a través de Socket.IO.

Widget → servidor

EventoPayload
joinchannelId, visitorId, visitorInfo { userAgent, currentUrl, referrer }
messageMensaje saliente del visitante
typingIndicador de escritura del visitante
heartbeatKeep-alive de presencia
tool:resultResultado de la ejecución de una herramienta del lado del cliente
tool:errorError de la ejecución de una herramienta del lado del cliente

Servidor → widget

EventoPayload
joinedconversationId, messages iniciales, config del widget, faqs. La conversación solo se crea cuando el visitante envía su primer mensaje, por lo que para un visitante nuevo conversationId es null y messages está vacío; un visitante que vuelve con una conversación abierta recibe su id y su historial. No dependa del id antes del primer mensaje.
messageNuevo mensaje del agente
agent_typingIndicador de escritura del agente
tool:executeSolicitud para ejecutar una herramienta del lado del cliente en el navegador

Tarjetas de producto#

Cuando una respuesta enlaza a la página de un producto de tu tienda, el widget muestra el enlace como una tarjeta: imagen, nombre, precio, stock y un botón Añadir al carrito. Funciona como una vista previa de enlace y no requiere configuración. Las respuestas de la IA, los borradores aprobados y las respuestas que escribe tu equipo reciben tarjetas.

Tarjetas de producto bajo una respuesta del chat y la misma tarjeta tras tocar Añadir al carrito
Tarjetas de producto bajo una respuesta del chat y la misma tarjeta tras tocar Añadir al carrito

De dónde salen los datos. Cuando se entrega la respuesta, HelpStack abre la página enlazada y lee los datos del producto que tu tienda ya publica para los buscadores: datos estructurados schema.org Product (JSON-LD o microdatos) y, como alternativa, las etiquetas Open Graph (og:title, og:image, product:price:amount). WooCommerce los publica por defecto, igual que la mayoría de los temas de Shopify. La tarjeta nunca sale del texto de la respuesta, así que la IA no puede inventarse un precio: un enlace que no carga, o una página que no es un producto (la página de envíos, una entrada del blog), sigue siendo un enlace normal.

Las tiendas Shopify conectadas se leen mediante la Shopify Admin API en lugar de la página: el precio, el stock y las variantes vienen directamente de Shopify, y también funciona en una tienda de desarrollo protegida con contraseña.

Qué enlaces se abren. Solo los de tus propios sitios: la lista de dominios permitidos del widget, la página en la que está el visitante y una tienda Shopify o WooCommerce conectada. Cada petición pasa por la misma protección contra direcciones privadas que las herramientas personalizadas, también en las redirecciones. Las páginas se guardan en caché una hora, así que un producto popular cuesta una petición por hora.

Límites. Como máximo 3 tarjetas por respuesta. Si tu tienda no responde en unos segundos, la respuesta se envía sin tarjetas en lugar de tarde.

Los botones

Una tarjeta tiene hasta dos botones. El primero es:

SituaciónBotón principal
AgotadoAgotado (desactivado)
El visitante tiene que elegir talla o color primeroElegir opciones: abre la página del producto
Tu página puede añadirlo al carritoAñadir al carrito
En otro casoVer producto

El segundo botón es uno tuyo (ver abajo) o Ver producto. Cuando Añadir al carrito funciona, el botón pasa a Añadido · Ver carrito. Los enlaces a tu tienda se abren en la misma pestaña, como cualquier enlace de tu tienda; el chat sigue en la conversación tras el cambio de página.

Shopify y WooCommerce funcionan sin configurar nada. En una tienda Shopify el widget añade la variante mediante el /cart/add.js de la propia tienda; en WooCommerce añade mediante la Store API de WooCommerce, que tienen tanto los temas de bloques como los clásicos (con el endpoint clásico de añadir al carrito como alternativa), y avisa al minicarrito para que se actualice. Un producto de Shopify con varias variantes muestra Elegir opciones, salvo que el enlace apunte a una variante (?variant=123). El carrito integrado solo añade productos de la tienda en la que está el visitante.

Tus propios botones

Registra un manejador con forProducts: true y aparecerá en cada tarjeta. Recibe el producto:

<script>
  window.HelpStack = window.HelpStack || function () {
    (window.HelpStack.q = window.HelpStack.q || []).push(arguments);
  };

  window.HelpStack('registerAction', 'wishlist', async (product) => {
    // product: { url, title, productId, variantId, price, currency, platform, quantity }
    await myWishlist.add(product.productId);
    return { ok: true };
  }, { forProducts: true, label: { en: 'Save for later', es: 'Guardar para después' } });
</script>
Opción
forProductstrue lo convierte en un botón de tarjeta en lugar de un botón «Muéstramelo»
labelTexto del botón: una cadena o uno por idioma ({ en, sl, de, ... }), elegido según el idioma del navegador del visitante. Como máximo 40 caracteres
primarytrue pone tu botón primero, antes de Añadir al carrito

El nombre add_to_cart es especial: se convierte en el botón Añadir al carrito de la tarjeta y sustituye al integrado de Shopify/WooCommerce. Úsalo con cualquier otro sistema de tienda. Devuelve { ok: true, cartUrl: '/cart' } para que Ver carrito lleve a tu página de carrito, o { ok: false, message } para mostrar un fallo bajo la tarjeta.

Los manejadores siguen las mismas reglas que los botones de acción: 10 segundos por toque, y un error lanzado cuenta como fallo.

Qué sabe la IA

En el chat web se pide a la IA que incluya el enlace de cada producto que recomienda, solo enlaces obtenidos de una herramienta o de la base de conocimiento, y como máximo 3 por respuesta. Cuando el visitante toca un botón de una tarjeta, la IA lo lee en su siguiente turno («tocó Añadir al carrito en la tarjeta de Bici de trail 29" y funcionó») y puede seguir a partir de ahí. Cada toque se registra como una fila CLIENT_ACTION en los registros de herramientas, con el nombre del botón (add_to_cart, view_product, choose_options, view_cart o el tuyo).

Desactivar las tarjetas

Canales → Apariencia → Tarjetas de producto, o update_widget_config con productCards: false. Los enlaces siguen siendo enlaces normales.

Lista de dominios permitidos#

Un canal puede restringir qué orígenes pueden cargar el widget. Cuando se configura una lista y el origen solicitante no está en ella, el servidor responde con 403. Configure la lista en la configuración del canal en el panel de control. Déjela vacía para permitir cualquier origen.

Página de ejemplo mínima#

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>HelpStack Widget Demo</title>
  </head>
  <body>
    <h1>My website</h1>
    <button onclick="window.ChatWidget.open()">Need help?</button>

    <!-- HelpStack widget -->
    <script
      src="https://helpstack.eu/widget.js?id=CHANNEL_ID"
      async
    ></script>
  </body>
</html>

Relacionado#