# Referência do editor de widgets

> Referência de código dos widgets do editor de widgets do KickBot: todos os eventos da Kick e seus dados, globalValues, userVariables, funções de chat e a prévia.

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

Esta página lista o que o seu código pode usar em um widget do [editor de widgets](https://kickbot.com/pt/docs/widgets/widget-builder) do KickBot: os eventos `widgetEvent`, o objeto `globalValues`, o objeto `userVariables` e as funções auxiliares em `window.kickbotWidget`. Todo widget é HTML, CSS e JavaScript puro, que roda como browser source no OBS. O KickBot se conecta à Kick por você e envia os eventos para o seu código.

## Como um widget roda

Quando o OBS abre a URL do widget, o KickBot:

1. Carrega a página do widget com fundo transparente.
2. Coloca seu CSS em um elemento `<style>` e seu HTML na página.
3. Carrega os dados do seu canal da Kick (número de seguidores, número de espectadores, status da live e chat recente) em `globalValues`.
4. Roda seu JavaScript. Ele roda uma vez, depois do passo 3, então `globalValues` já está pronto quando seu código começa.
5. Envia os eventos ao vivo para o seu código como eventos `widgetEvent` em `document`.

Seu JavaScript pode ler dois objetos sem importar nada: `globalValues` e `userVariables`. As funções auxiliares ficam em `window.kickbotWidget`.

Limites:

| Item | Limite |
| --- | --- |
| Largura e altura | Definidas em **Configurações básicas**. Um widget novo em branco tem 800 × 600. A janela Novo widget aceita até 7680 × 4320. |
| HTML, CSS e JavaScript | Até 2.000.000 de caracteres por arquivo |
| Nome do widget | Até 500 caracteres |
| Arquivos das variáveis do usuário | Até 25 MB por arquivo |
| Widgets do editor no plano Grátis | 10 (sem limite no Premium) |

## Ouça os eventos

Adicione um listener para `widgetEvent` em `document`. Cada evento tem `event.detail` com três campos:

| Campo | Tipo | Valor |
| --- | --- | --- |
| `event_name` | string | O evento, por exemplo `followEvent` |
| `source` | string | Sempre `kick` |
| `data` | object | Os dados do evento (veja abaixo) |

```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

| Nome do evento | Quando dispara | Botão de teste |
| --- | --- | --- |
| `subEvent` | Um espectador se inscreve | Sub |
| `subGiftEvent` | Um espectador presenteia subs | Sub presenteada |
| `kicksEvent` | Um espectador envia KICKs | KICKs |
| `followEvent` | Um espectador segue | Follow |
| `unfollowEvent` | Um espectador deixa de seguir | Unfollow |
| `chatMessageEvent` | Uma mensagem é enviada no chat | Mensagem |
| `chatMessageDeletedEvent` | Um moderador apaga uma mensagem | Mensagem excluída |
| `chatMessagePinnedEvent` | Uma mensagem é fixada | Mensagem fixada |
| `chatMessageUnpinnedEvent` | A mensagem fixada é removida | Mensagem desafixada |
| `chatClearedEvent` | Um moderador limpa o chat | Chat limpo |
| `followerCountUpdatedEvent` | A Kick envia um novo número de seguidores | Contagem de followers atualizada |
| `subCountUpdatedEvent` | O número de subs na Kick mudou | Contagem de subs atualizada |
| `viewerCountUpdatedEvent` | A Kick envia um novo número de espectadores | Contagem de viewers atualizada |
| `raidEvent` | Outro canal faz raid (host) em você | Raid |
| `streamOnline` | Sua live começa | Stream ao vivo |
| `streamOffline` | Sua live termina | Stream offline |

Não existe evento de gorjeta. Para alertas de gorjeta, use o [widget de alerta de gorjeta](https://kickbot.com/pt/docs/tipping/tip-alerts).

### Dados dos eventos

Estes são os dados em `event.detail.data`. Eles são iguais aos dos eventos de teste no editor. Os eventos reais podem ter mais campos. Os nomes, números e IDs aqui são exemplos.

`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` e `unfollowEvent` (mesmo formato; `followers_count` é o novo número)

```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 }]
        }
    }
}
```

Os emotes da Kick ficam em `content` como `[emote:ID:NAME]`. Use `createChatMessageFragment` (veja [Mostre o texto do chat com segurança](#show-chat-text-safely)) para transformar os emotes em imagens.

`chatMessageDeletedEvent`

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

Use `data.message.id` para encontrar e remover a mensagem que você mostrou.

`chatMessagePinnedEvent` (`data.message` tem o mesmo formato dos dados de um `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` é um array vazio (`[]`).

`chatClearedEvent`

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

`followerCountUpdatedEvent` (atenção ao camelCase em `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 globais

`globalValues` guarda o estado atual do seu canal. O KickBot preenche o objeto antes de o seu código rodar e mantém tudo atualizado conforme os eventos chegam. Use esses valores para desenhar o widget no início, antes de chegar qualquer 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 | Como atualiza |
| --- | --- |
| `subCount` | Carregado da Kick. Sobe 1 a cada `subEvent` e 1 a cada sub presenteado, e é definido de novo por `subCountUpdatedEvent`. |
| `followerCount` | Carregado da Kick. Definido por `followEvent`, `unfollowEvent` e `followerCountUpdatedEvent`. |
| `viewerCount` | Carregado da Kick (0 quando você está offline). Definido por `viewerCountUpdatedEvent`. |
| `lastFollower`, `lastSub`, `lastGiftedSub` | O último que o KickBot viu no seu canal, ou `null`. Atualizado pelo evento correspondente. |
| `chatMessages` | O chat recente da Kick quando o widget carrega e depois cada mensagem nova. Guarda as 100 mais novas. `chatClearedEvent` esvazia a lista. Para esconder mensagens apagadas, trate `chatMessageDeletedEvent` no seu próprio código. |
| `streamerInfo.kick` | Seu perfil da Kick. Não muda enquanto o widget roda. |
| `currentStream` | Carregado da Kick quando o widget carrega. Não é atualizado por `streamOnline` nem por `streamOffline`. Ouça esses eventos se você precisa saber se está ao vivo. |

## Variáveis do usuário

As variáveis do usuário são as configurações que os streamers veem quando abrem o seu widget em Widgets salvos. Você adiciona as variáveis em **Variáveis do usuário** no editor. No código, leia o valor com `userVariables.<variable name>.value`.

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

Campos de uma variável:

| Campo | O que é |
| --- | --- |
| Título | O nome que os streamers veem. |
| Nome da variável | O nome no seu código. Só letras, números e `_`. Você não pode mudar depois de criar a variável. |
| Tooltip | Texto extra de ajuda abaixo do título. |
| Tipo de variável | Veja a tabela abaixo. |
| Valor padrão | O valor antes de o streamer mudar. Pode ficar vazio. |
| Obrigatória | Os streamers precisam preencher um valor antes de salvar. |

| Tipo | O que o streamer vê | `value` no seu código |
| --- | --- | --- |
| Texto | Uma caixa de texto | Uma string |
| Número | Uma caixa de número | Um número ou uma string numérica. Use `Number()` para garantir. |
| Cor | Um seletor de cor | Uma string com a cor em hex, por exemplo `#ffffff` |
| Dropdown | Um menu com as suas opções | A opção escolhida, como string. O padrão é a primeira opção. |
| Toggle | Uma chave de ligar e desligar | `true` ou `false` |
| Imagem/GIF | Uma caixa de URL e um botão de envio | Uma URL para o arquivo |
| Vídeo | Uma caixa de URL e um botão de envio | Uma URL para o arquivo |
| Áudio | Uma caixa de URL e um botão de envio | Uma URL para o arquivo |

Os arquivos enviados ficam guardados no KickBot, e `value` é a URL do arquivo. Use o menu ao lado de uma variável para mover para cima ou para baixo, editar ou excluir. A ordem no editor é a ordem que os streamers veem.

## Mostre o texto do chat com segurança

Trate todo campo de evento e toda variável do usuário como texto de um desconhecido. O KickBot limpa o texto do chat e dos eventos antes de ele chegar ao seu código, então ele é seguro como texto HTML, mas não como URL, CSS ou script. Não coloque campos de evento crus em `innerHTML`. Use estas funções auxiliares:

| Função auxiliar | O que faz |
| --- | --- |
| `window.kickbotWidget.createChatMessageFragment(content, font_size)` | Retorna um `DocumentFragment` com nós de texto e imagens dos emotes da Kick. Os emotes têm `font_size + 3` pixels. `font_size` é 20 por padrão. |
| `window.kickbotWidget.createTextNode(value)` | Retorna um nó de texto para qualquer valor. |
| `window.kickbotWidget.escapeHtmlText(value)` | Escapa o texto para usar entre tags HTML quando você precisa montar uma string HTML. Não use para URLs, CSS ou script. |

```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 outros textos, use `textContent` ou `createTextNode`.

## A prévia

A prévia no editor funciona como o OBS, com algumas diferenças para testes:

- Quando você muda o código ou uma variável do usuário, a prévia roda seu JavaScript de novo. Antes, o KickBot remove os listeners de `widgetEvent` da execução anterior. Os timers de `setInterval` e `setTimeout` não são removidos, então clique no botão de recarregar se eles se acumularem.
- Quando você muda a largura ou a altura, a prévia recarrega.
- Os eventos de teste vão só para a prévia. Um **Follow** de teste soma 1 em `globalValues.followerCount`, e **Unfollow** tira 1. **Contagem de viewers atualizada** envia um número de exemplo. **Mensagem excluída** remove uma mensagem aleatória do chat da prévia.
- Se o seu canal ainda não tem último seguidor, sub ou sub presenteado, a prévia usa dados de exemplo para `lastFollower`, `lastSub` e `lastGiftedSub`.
- Para ver a saída de `console.log` e os erros, clique no botão de abrir em janela separada e abra as ferramentas de desenvolvedor nessa janela.

## Exemplo: meta de seguidores

Esta é uma meta de seguidores curta. Ela usa um listener de evento, `globalValues` e duas variáveis do usuário: `follower_goal` (Número) e `bar_color` (Cor).

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 uma versão completa com mais configurações, comece um widget novo pelo template **Simple Follower Goal**.

## Dicas

- Desenhe o primeiro estado a partir de `globalValues` e depois mude com os eventos. Um widget que espera um evento fica vazio até alguma coisa acontecer.
- Widgets salvos só mostra botões de teste para os nomes de evento que aparecem no seu JavaScript. Escreva o nome completo do evento (por exemplo `'followEvent'`) no código para os streamers poderem testar seu widget.
- Deixe o fundo transparente, a não ser que um fundo faça parte do design, para o widget ficar por cima da cena.
- Você também pode gerenciar os widgets do editor com a API do KickBot. Veja a [referência da API de widgets](https://kickbot.com/docs/api/reference/widgets) (em inglês).
