# Referencia del Editor de widgets

> Referencia de código del Editor de widgets de KickBot: cada evento de Kick y sus datos, globalValues, userVariables y las ayudas para el chat y la vista previa.

Source: https://kickbot.com/es/docs/widgets/widget-builder-reference

Esta página lista lo que tu código puede usar en un widget del [Editor de widgets](https://kickbot.com/es/docs/widgets/widget-builder) de KickBot: los eventos `widgetEvent`, el objeto `globalValues`, el objeto `userVariables` y las funciones de ayuda de `window.kickbotWidget`. Cada widget es HTML, CSS y JavaScript normal que se ejecuta como fuente de navegador en OBS. KickBot se conecta a Kick por ti y envía los eventos a tu código.

## Cómo se ejecuta un widget

Cuando OBS abre la URL del widget, KickBot:

1. Carga la página del widget con un fondo transparente.
2. Añade tu CSS en un elemento `<style>` y pone tu HTML en la página.
3. Carga en `globalValues` los datos de tu canal desde Kick (número de seguidores, número de espectadores, estado del stream y chat reciente).
4. Ejecuta tu JavaScript. Se ejecuta una vez, después del paso 3, así que `globalValues` ya está listo cuando empieza tu código.
5. Envía los eventos en vivo a tu código como eventos `widgetEvent` en `document`.

Tu JavaScript puede leer dos objetos sin importar nada: `globalValues` y `userVariables`. Las funciones de ayuda están en `window.kickbotWidget`.

Límites:

| Elemento | Límite |
| --- | --- |
| Ancho y alto | Se ajustan en **Ajustes básicos**. Un widget nuevo en blanco mide 800 × 600. La ventana Nuevo widget acepta hasta 7680 × 4320. |
| HTML, CSS y JavaScript | Hasta 2,000,000 caracteres por archivo |
| Nombre del widget | Hasta 500 caracteres |
| Archivos para variables de usuario | Hasta 25 MB por archivo |
| Widgets del editor en el plan Gratis | 10 (sin límite con Premium) |

## Escucha los eventos

Añade un listener de `widgetEvent` en `document`. Cada evento tiene `event.detail` con tres campos:

| Campo | Tipo | Valor |
| --- | --- | --- |
| `event_name` | string | El evento, por ejemplo `followEvent` |
| `source` | string | Siempre `kick` |
| `data` | object | Los datos del evento (ver abajo) |

```javascript
document.addEventListener('widgetEvent', (event) => {
    const { event_name, data } = event.detail;

    if (event_name === 'followEvent') {
        showAlert(data.user.username + ' followed!');
    }
    if (event_name === 'subEvent') {
        showAlert(data.username + ' subscribed for ' + data.months + ' months');
    }
});
```

### Lista de eventos

| Nombre del evento | Cuándo se dispara | Botón de prueba |
| --- | --- | --- |
| `subEvent` | Un espectador se suscribe | Sub |
| `subGiftEvent` | Un espectador regala subs | Sub regalado |
| `kicksEvent` | Un espectador envía KICKs | KICKs |
| `followEvent` | Un espectador te sigue | Follow |
| `unfollowEvent` | Un espectador deja de seguirte | Unfollow |
| `chatMessageEvent` | Se envía un mensaje en el chat | Mensaje |
| `chatMessageDeletedEvent` | Un moderador elimina un mensaje | Mensaje eliminado |
| `chatMessagePinnedEvent` | Se fija un mensaje | Mensaje fijado |
| `chatMessageUnpinnedEvent` | Se quita el mensaje fijado | Mensaje desfijado |
| `chatClearedEvent` | Un moderador limpia el chat | Chat limpiado |
| `followerCountUpdatedEvent` | Kick envía un nuevo número de seguidores | Recuento de followers actualizado |
| `subCountUpdatedEvent` | Cambió el número de subs en Kick | Recuento de subs actualizado |
| `viewerCountUpdatedEvent` | Kick envía un nuevo número de espectadores | Recuento de espectadores actualizado |
| `raidEvent` | Otro canal te hace un raid (host) | Raid |
| `streamOnline` | Empieza tu stream | Stream en directo |
| `streamOffline` | Termina tu stream | Stream offline |

No hay un evento de propina. Para las alertas de propina, usa el [widget de alertas de propina](https://kickbot.com/es/docs/tipping/tip-alerts).

### Datos de los eventos

Estos son los datos que llegan en `event.detail.data`. Coinciden con los eventos de prueba del editor. Los eventos reales pueden tener más campos. Los nombres, números e IDs de aquí son ejemplos.

`subEvent`

```javascript
{
    months: 1,
    username: 'viewer_one',
    chatroom_id: 3847194
}
```

`subGiftEvent`

```javascript
{
    chatroom_id: 3847194,
    gifted_usernames: ['viewer_one', 'viewer_two', 'viewer_three'],
    gifter_username: 'big_gifter'
}
```

`kicksEvent`

```javascript
{
    message: 'Great stream!',
    sender: { id: 12345678, username: 'viewer_one', username_color: '#93EBE0' },
    gift: {
        gift_id: 'full_send',
        name: 'Full Send',
        amount: 100,
        type: 'BASIC',
        tier: 'BASIC',
        character_limit: 0,
        pinned_time: 0
    },
    channel: 'channel_3984507'
}
```

`followEvent` y `unfollowEvent` (misma forma; `followers_count` es el número nuevo)

```javascript
{
    id: 'd4e5f6a7-89b0-12c3-d456-78901e2f3a4b',
    channel: { id: 3984507, slug: 'kickbotdev' },
    user: { id: 14873539, slug: 'viewer_one', username: 'viewer_one' },
    followers_count: 36,
    created_at: '2024-05-13T22:19:07+00:00'
}
```

`chatMessageEvent`

```javascript
{
    id: '85c884b3-7377-478c-b6aa-22b7db752b93',
    chatroom_id: 3974112,
    content: 'hello [emote:37226:KEKW]',
    type: 'message',
    created_at: '2024-05-13T22:29:52+00:00',
    sender: {
        id: 4063326,
        username: 'viewer_one',
        slug: 'viewer_one',
        identity: {
            color: '#72ACED',
            badges: [{ type: 'subscriber', text: 'Subscriber', count: 3 }]
        }
    }
}
```

Los emotes de Kick están en `content` como `[emote:ID:NAME]`. Usa `createChatMessageFragment` (consulta [Muestra el texto del chat de forma segura](#show-chat-text-safely)) para convertirlos en imágenes.

`chatMessageDeletedEvent`

```javascript
{
    id: '9cd3788a-ecd2-4051-a162-a7ea9be8ce7a',
    message: { id: '89d6be86-63db-4581-922e-14a6c4a9c2e6' }
}
```

Usa `data.message.id` para encontrar y quitar el mensaje que mostraste.

`chatMessagePinnedEvent` (`data.message` tiene la misma forma que los datos de un `chatMessageEvent`)

```javascript
{
    message: {
        id: '5d798a38-ad17-45e4-8169-bda2faa85b79',
        chatroom_id: 3974112,
        content: 'This is a pinned message!',
        type: 'message',
        created_at: '2024-05-13T22:30:41+00:00',
        sender: { id: 4063326, username: 'kickbotdev', slug: 'kickbotdev', identity: { color: '#72ACED', badges: [] } }
    }
}
```

`chatMessageUnpinnedEvent`: `data` es un array vacío (`[]`).

`chatClearedEvent`

```javascript
{ id: '47e3596f-0274-46e0-85b1-029fa3bfc5ea' }
```

`followerCountUpdatedEvent` (fíjate en el camelCase de `followersCount`)

```javascript
{ followersCount: 1532, channel_id: 4599, created_at: 1715639984 }
```

`subCountUpdatedEvent`

```javascript
{ subscriber_count: 184, channel_id: 4599 }
```

`viewerCountUpdatedEvent`

```javascript
{ viewer_count: 320, channel_id: 5937485 }
```

`raidEvent`

```javascript
{
    chatroom_id: 839485,
    optional_message: 'gg stream',
    number_viewers: 150,
    host_username: 'raiding_channel'
}
```

`streamOnline`

```javascript
{
    livestream: {
        id: 3984507,
        channel_id: 3984507,
        session_title: 'Test stream!',
        created_at: '2024-05-13T22:30:41+00:00'
    }
}
```

`streamOffline`

```javascript
{
    livestream: {
        id: 3984507,
        channel: { id: 3984507, is_banned: false }
    }
}
```

## Valores globales

`globalValues` guarda el estado actual de tu canal. KickBot lo rellena antes de que se ejecute tu código y lo mantiene al día a medida que llegan eventos. Úsalo para dibujar tu widget al principio, antes de que llegue ningún evento.

```javascript
globalValues = {
    subCount: 184,
    followerCount: 1532,
    viewerCount: 320,
    lastFollower: { /* the last follow */ },
    lastSub: { /* the last sub, for example { username, months } */ },
    lastGiftedSub: { /* the last gift, for example { gifter_username, gifted_usernames } */ },
    chatMessages: [ /* chatMessageEvent payloads */ ],
    streamerInfo: {
        kick: {
            username: 'KickBotDev',
            slug: 'kickbotdev',
            profile_picture: 'https://files.kick.com/images/user/.../fullsize.webp',
            user_id: '4063326',
            channel_id: '3984507',
            chatroom_id: '3974112',
            bio: 'Channel bio',
            subscriber_badges: [ /* your channel's sub badges from Kick */ ]
        }
    },
    currentStream: {
        is_live: true,
        title: 'Stream title',
        started_at: '2026-10-24 18:00:00'
    }
}
```

| Valor | Cómo se actualiza |
| --- | --- |
| `subCount` | Se carga desde Kick. Sube 1 con cada `subEvent` y 1 con cada sub regalado, y `subCountUpdatedEvent` lo vuelve a fijar. |
| `followerCount` | Se carga desde Kick. Lo fijan `followEvent`, `unfollowEvent` y `followerCountUpdatedEvent`. |
| `viewerCount` | Se carga desde Kick (0 cuando no estás en vivo). Lo fija `viewerCountUpdatedEvent`. |
| `lastFollower`, `lastSub`, `lastGiftedSub` | El último que KickBot vio en tu canal, o `null`. Se actualiza con el evento correspondiente. |
| `chatMessages` | El chat reciente de Kick cuando carga el widget, y después cada mensaje nuevo. Guarda los 100 más recientes. `chatClearedEvent` lo vacía. Para ocultar los mensajes eliminados, gestiona `chatMessageDeletedEvent` en tu propio código. |
| `streamerInfo.kick` | Tu perfil de Kick. No cambia mientras el widget se ejecuta. |
| `currentStream` | Se carga desde Kick cuando carga el widget. `streamOnline` y `streamOffline` no lo actualizan. Escucha esos eventos si necesitas saber si estás en vivo en cada momento. |

## Variables de usuario

Las variables de usuario son los ajustes que ven los streamers cuando abren tu widget en Widgets guardados. Las añades en **Variables de usuario**, en el editor. En tu código, lee el valor con `userVariables.<variable name>.value`.

```javascript
const goal = Number(userVariables.follower_goal.value);
document.body.style.color = userVariables.text_color.value;
```

Campos de una variable:

| Campo | Qué es |
| --- | --- |
| Título | El nombre que ven los streamers. |
| Nombre de la variable | El nombre en tu código. Solo letras, números y `_`. No puedes cambiarlo después de crear la variable. |
| Tooltip | Texto de ayuda extra debajo del título. |
| Tipo de variable | Consulta la tabla de abajo. |
| Valor por defecto | El valor antes de que el streamer lo cambie. Puede estar vacío. |
| Obligatoria | Los streamers tienen que escribir un valor antes de poder guardar. |

| Tipo | Lo que ve el streamer | `value` en tu código |
| --- | --- | --- |
| Texto | Un cuadro de texto | Un string |
| Número | Un cuadro numérico | Un número o un string numérico. Usa `Number()` para ir sobre seguro. |
| Color | Un selector de color | Un string con un color hex, por ejemplo `#ffffff` |
| Desplegable | Un menú con tus opciones | La opción elegida como string. Por defecto es la primera opción. |
| Interruptor | Un interruptor de activar y desactivar | `true` o `false` |
| Imagen/GIF | Un cuadro de URL y un botón para subir | Una URL al archivo |
| Vídeo | Un cuadro de URL y un botón para subir | Una URL al archivo |
| Audio | Un cuadro de URL y un botón para subir | Una URL al archivo |

KickBot guarda los archivos subidos, y `value` es la URL del archivo. Usa el menú junto a una variable para subirla o bajarla, editarla o eliminarla. El orden en el editor es el orden que ven los streamers.

## Muestra el texto del chat de forma segura

Trata cada campo de un evento y cada variable de usuario como texto de un desconocido. KickBot limpia el texto del chat y de los eventos antes de que llegue a tu código, así que es seguro como texto HTML, pero no como URL, CSS o script. No pongas campos de eventos sin procesar en `innerHTML`. Usa estas funciones de ayuda:

| Función de ayuda | Qué hace |
| --- | --- |
| `window.kickbotWidget.createChatMessageFragment(content, font_size)` | Devuelve un `DocumentFragment` con nodos de texto e imágenes de los emotes de Kick. Los emotes miden `font_size + 3` píxeles. `font_size` es 20 por defecto. |
| `window.kickbotWidget.createTextNode(value)` | Devuelve un nodo de texto para cualquier valor. |
| `window.kickbotWidget.escapeHtmlText(value)` | Escapa el texto para usarlo entre etiquetas HTML cuando tienes que construir un string de HTML. No lo uses para URLs, CSS ni scripts. |

```javascript
document.addEventListener('widgetEvent', (event) => {
    if (event.detail.event_name !== 'chatMessageEvent') return;
    const data = event.detail.data;

    const line = document.createElement('div');
    line.id = 'msg-' + data.id;
    const name = document.createElement('strong');
    name.style.color = data.sender.identity.color;
    name.append(window.kickbotWidget.createTextNode(data.sender.username + ': '));
    line.append(name);
    line.append(window.kickbotWidget.createChatMessageFragment(data.content, 20));
    document.getElementById('chat').append(line);
});
```

Para otros textos, usa `textContent` o `createTextNode`.

## La vista previa

La vista previa del editor funciona como OBS, con algunas diferencias para hacer pruebas:

- Cuando cambias el código o una variable de usuario, la vista previa vuelve a ejecutar tu JavaScript. Antes, KickBot quita los listeners de `widgetEvent` de la ejecución anterior. Los temporizadores de `setInterval` y `setTimeout` no se quitan, así que haz clic en el botón de recargar si se acumulan.
- Cuando cambias el ancho o el alto, la vista previa se recarga.
- Los eventos de prueba solo van a la vista previa. Un **Follow** de prueba suma 1 a `globalValues.followerCount`, y **Unfollow** resta 1. **Recuento de espectadores actualizado** envía un número de ejemplo. **Mensaje eliminado** quita un mensaje al azar del chat de la vista previa.
- Si tu canal todavía no tiene un último seguidor, sub o sub regalado, la vista previa usa datos de ejemplo para `lastFollower`, `lastSub` y `lastGiftedSub`.
- Para ver la salida de `console.log` y los errores, haz clic en el botón de ventana aparte y abre las herramientas de desarrollador en esa ventana.

## Ejemplo: meta de seguidores

Esta es una meta de seguidores corta. Usa un listener de eventos, `globalValues` y dos variables de usuario: `follower_goal` (Número) y `bar_color` (Color).

HTML:

```html
<div class="goal">
    <span id="count"></span> / <span id="target"></span>
    <div class="bar"><div class="fill"></div></div>
</div>
```

CSS:

```css
body { margin: 0; font-family: Arial, sans-serif; color: #fff; }
.goal { padding: 12px; background: #100c28; border-radius: 16px; font-size: 32px; font-weight: bold; }
.bar { height: 24px; margin-top: 8px; background: #3d3957; border-radius: 12px; overflow: hidden; }
.fill { height: 100%; width: 0; transition: width 0.3s ease; }
```

JavaScript:

```javascript
const target = Number(userVariables.follower_goal.value) || 100;
document.getElementById('target').textContent = target;
document.querySelector('.fill').style.background = userVariables.bar_color.value;

function update(count) {
    document.getElementById('count').textContent = count;
    document.querySelector('.fill').style.width = Math.min((count / target) * 100, 100) + '%';
}

document.addEventListener('widgetEvent', (event) => {
    const { event_name, data } = event.detail;
    if (event_name === 'followEvent' || event_name === 'unfollowEvent') update(data.followers_count);
    if (event_name === 'followerCountUpdatedEvent') update(data.followersCount);
});

update(globalValues.followerCount);
```

Para una versión completa con más ajustes, empieza un widget nuevo desde la plantilla **Simple Follower Goal**.

## Consejos

- Dibuja el primer estado desde `globalValues` y después cámbialo con los eventos. Un widget que espera un evento se ve vacío hasta que pasa algo.
- Widgets guardados solo muestra botones de prueba para los nombres de eventos que aparecen en tu JavaScript. Escribe el nombre completo del evento (por ejemplo `'followEvent'`) en tu código para que los streamers puedan probar tu widget.
- Deja el fondo transparente, salvo que el fondo sea parte del diseño, para que el widget quede encima de la escena.
- También puedes gestionar los widgets del editor con la API de KickBot. Consulta la [referencia de la API de widgets](https://kickbot.com/docs/api/reference/widgets).
