# Widget-Builder-Referenz

> Code-Referenz für Widgets aus dem KickBot Widget Builder: alle Kick-Events mit Payload, globalValues, userVariables, Chat-Helfer und wie die Vorschau Code ausführt.

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

Diese Seite listet, was dein Code in einem Widget aus dem KickBot [Widget Builder](https://kickbot.com/de/docs/widgets/widget-builder) nutzen kann: die `widgetEvent`-Events, das Objekt `globalValues`, das Objekt `userVariables` und die Helfer in `window.kickbotWidget`. Jedes Widget ist einfaches HTML, CSS und JavaScript, das als Browser-Source in OBS läuft. KickBot verbindet sich für dich mit Kick und schickt Events an deinen Code.

## So läuft ein Widget

Wenn OBS die Widget-URL öffnet, macht KickBot Folgendes:

1. Lädt die Widget-Seite mit transparentem Hintergrund.
2. Fügt dein CSS in einem `<style>`-Element ein und setzt dein HTML in die Seite.
3. Lädt deine Kanaldaten von Kick (Follower-Zahl, Zuschauerzahl, Stream-Status und letzte Chat-Nachrichten) in `globalValues`.
4. Führt dein JavaScript aus. Es läuft einmal, nach Schritt 3. `globalValues` ist also bereit, wenn dein Code startet.
5. Schickt Live-Events als `widgetEvent`-Events auf `document` an deinen Code.

Dein JavaScript kann zwei Objekte lesen, ohne etwas zu importieren: `globalValues` und `userVariables`. Die Helfer liegen in `window.kickbotWidget`.

Limits:

| Punkt | Limit |
| --- | --- |
| Breite und Höhe | Wird unter **Grundeinstellungen** eingestellt. Ein neues leeres Widget hat 800 × 600. Das Popup Neues Widget erlaubt bis zu 7680 × 4320. |
| HTML, CSS und JavaScript | Bis zu 2.000.000 Zeichen pro Datei |
| Widget-Name | Bis zu 500 Zeichen |
| Dateien für Nutzervariablen | Bis zu 25 MB pro Datei |
| Builder-Widgets im Gratis-Plan | 10 (kein Limit mit Premium) |

## Auf Events hören

Füge einen Listener für `widgetEvent` auf `document` hinzu. Jedes Event hat `event.detail` mit drei Feldern:

| Feld | Typ | Wert |
| --- | --- | --- |
| `event_name` | string | Das Event, zum Beispiel `followEvent` |
| `source` | string | Immer `kick` |
| `data` | object | Die Payload des Events (siehe unten) |

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

### Liste der Events

| Event-Name | Wann es ausgelöst wird | Test-Button |
| --- | --- | --- |
| `subEvent` | Ein Zuschauer subbt | Sub |
| `subGiftEvent` | Ein Zuschauer verschenkt Subs | Gifted Sub |
| `kicksEvent` | Ein Zuschauer sendet KICKs | KICKs |
| `followEvent` | Ein Zuschauer folgt | Follow |
| `unfollowEvent` | Ein Zuschauer entfolgt | Unfollow |
| `chatMessageEvent` | Eine Chat-Nachricht wird gesendet | Nachricht |
| `chatMessageDeletedEvent` | Ein Moderator löscht eine Nachricht | Nachricht gelöscht |
| `chatMessagePinnedEvent` | Eine Nachricht wird angepinnt | Nachricht angepinnt |
| `chatMessageUnpinnedEvent` | Die angepinnte Nachricht wird entfernt | Nachricht abgepinnt |
| `chatClearedEvent` | Ein Moderator leert den Chat | Chat geleert |
| `followerCountUpdatedEvent` | Kick schickt eine neue Follower-Zahl | Follower-Zahl aktualisiert |
| `subCountUpdatedEvent` | Die Sub-Zahl auf Kick hat sich geändert | Sub-Zahl aktualisiert |
| `viewerCountUpdatedEvent` | Kick schickt eine neue Zuschauerzahl | Viewer-Zahl aktualisiert |
| `raidEvent` | Ein anderer Kanal raidet (hostet) dich | Raid |
| `streamOnline` | Dein Stream startet | Stream online |
| `streamOffline` | Dein Stream endet | Stream offline |

Es gibt kein Tip-Event. Für Tip-Alerts nutze das [Tip-Alert-Widget](https://kickbot.com/de/docs/tipping/tip-alerts).

### Payloads der Events

Das sind die Payloads in `event.detail.data`. Sie entsprechen den Test-Events im Editor. Echte Events können mehr Felder haben. Namen, Zahlen und IDs hier sind Beispiele.

`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` und `unfollowEvent` (gleicher Aufbau; `followers_count` ist die neue Zahl)

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

Kick-Emotes stehen in `content` als `[emote:ID:NAME]`. Mit `createChatMessageFragment` (siehe [Chat-Text sicher anzeigen](#show-chat-text-safely)) machst du daraus Bilder.

`chatMessageDeletedEvent`

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

Mit `data.message.id` findest und entfernst du die Nachricht, die du angezeigt hast.

`chatMessagePinnedEvent` (`data.message` hat denselben Aufbau wie eine `chatMessageEvent`-Payload)

```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` ist ein leeres Array (`[]`).

`chatClearedEvent`

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

`followerCountUpdatedEvent` (achte auf das camelCase in `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 }
    }
}
```

## Globale Werte

`globalValues` enthält den aktuellen Stand deines Kanals. KickBot füllt es, bevor dein Code läuft, und hält es aktuell, während Events eintreffen. Nutze es, um dein Widget zum Start zu zeichnen, bevor ein Event ankommt.

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

| Wert | Wie er aktualisiert wird |
| --- | --- |
| `subCount` | Wird von Kick geladen. Steigt bei jedem `subEvent` um 1 und bei jedem Gifted Sub um 1 und wird durch `subCountUpdatedEvent` neu gesetzt. |
| `followerCount` | Wird von Kick geladen. Wird durch `followEvent`, `unfollowEvent` und `followerCountUpdatedEvent` gesetzt. |
| `viewerCount` | Wird von Kick geladen (0, wenn du offline bist). Wird durch `viewerCountUpdatedEvent` gesetzt. |
| `lastFollower`, `lastSub`, `lastGiftedSub` | Der letzte, den KickBot auf deinem Kanal gesehen hat, oder `null`. Wird durch das passende Event aktualisiert. |
| `chatMessages` | Die letzten Chat-Nachrichten von Kick beim Laden des Widgets, danach jede neue Nachricht. Behält die neuesten 100. `chatClearedEvent` leert es. Um gelöschte Nachrichten auszublenden, verarbeite `chatMessageDeletedEvent` in deinem eigenen Code. |
| `streamerInfo.kick` | Dein Kick-Profil. Ändert sich nicht, während das Widget läuft. |
| `currentStream` | Wird beim Laden des Widgets von Kick geladen. Es wird nicht durch `streamOnline` oder `streamOffline` aktualisiert. Hör auf diese Events, wenn du den Live-Status brauchst. |

## Nutzervariablen

Nutzervariablen sind die Einstellungen, die Streamer sehen, wenn sie dein Widget unter Gespeicherte Widgets öffnen. Du fügst sie im Editor unter **Nutzervariablen** hinzu. In deinem Code liest du den Wert mit `userVariables.<variable name>.value`.

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

Felder einer Variable:

| Feld | Was es ist |
| --- | --- |
| Titel | Das Label, das Streamer sehen. |
| Variablenname | Der Name in deinem Code. Nur Buchstaben, Zahlen und `_`. Du kannst ihn nicht ändern, nachdem du die Variable erstellt hast. |
| Tooltip | Zusätzlicher Hilfetext unter dem Titel. |
| Variablentyp | Siehe die Tabelle unten. |
| Standardwert | Der Wert, bevor der Streamer ihn ändert. Er darf leer sein. |
| Pflichtfeld | Streamer müssen einen Wert eingeben, bevor sie speichern können. |

| Typ | Was der Streamer sieht | `value` in deinem Code |
| --- | --- | --- |
| Text | Ein Textfeld | Ein String |
| Zahl | Ein Zahlenfeld | Eine Zahl oder ein numerischer String. Nutze `Number()`, um sicherzugehen. |
| Farbe | Eine Farbauswahl | Ein Hex-Farbwert als String, zum Beispiel `#ffffff` |
| Dropdown | Ein Menü mit deinen Optionen | Die gewählte Option als String. Standard ist die erste Option. |
| Schalter | Ein An/Aus-Schalter | `true` oder `false` |
| Bild/GIF | Ein URL-Feld und ein Upload-Button | Eine URL zur Datei |
| Video | Ein URL-Feld und ein Upload-Button | Eine URL zur Datei |
| Audio | Ein URL-Feld und ein Upload-Button | Eine URL zur Datei |

Hochgeladene Dateien speichert KickBot, und `value` ist die URL der Datei. Mit dem Menü neben einer Variable verschiebst du sie nach oben oder unten, bearbeitest oder löschst sie. Die Reihenfolge im Editor ist die Reihenfolge, die Streamer sehen.

## Chat-Text sicher anzeigen

Behandle jedes Event-Feld und jede Nutzervariable wie Text von einem Fremden. KickBot bereinigt Chat- und Event-Texte, bevor dein Code sie bekommt. Sie sind also als HTML-Text sicher, aber nicht als URL, CSS oder Skript. Setz rohe Event-Felder nicht in `innerHTML` ein. Nutze diese Helfer:

| Helfer | Was er macht |
| --- | --- |
| `window.kickbotWidget.createChatMessageFragment(content, font_size)` | Gibt ein `DocumentFragment` mit Textknoten und Kick-Emote-Bildern zurück. Emotes sind `font_size + 3` Pixel groß. `font_size` ist standardmäßig 20. |
| `window.kickbotWidget.createTextNode(value)` | Gibt für jeden Wert einen Textknoten zurück. |
| `window.kickbotWidget.escapeHtmlText(value)` | Escapt Text für die Nutzung zwischen HTML-Tags, wenn du einen HTML-String bauen musst. Nutze es nicht für URLs, CSS oder Skripte. |

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

Für anderen Text nutze `textContent` oder `createTextNode`.

## Die Vorschau

Die Vorschau im Editor funktioniert wie OBS, mit ein paar Unterschieden zum Testen:

- Wenn du den Code oder eine Nutzervariable änderst, führt die Vorschau dein JavaScript neu aus. KickBot entfernt vorher die `widgetEvent`-Listener des letzten Durchlaufs. Timer aus `setInterval` und `setTimeout` werden nicht entfernt. Klick also auf den Neu-laden-Button, wenn sie sich ansammeln.
- Wenn du Breite oder Höhe änderst, lädt die Vorschau neu.
- Test-Events gehen nur an die Vorschau. Ein Test-**Follow** zählt 1 zu `globalValues.followerCount` dazu, und **Unfollow** zieht 1 ab. **Viewer-Zahl aktualisiert** sendet eine Beispielzahl. **Nachricht gelöscht** entfernt eine zufällige Nachricht aus dem Chat der Vorschau.
- Wenn dein Kanal noch keinen letzten Follower, Sub oder Gifted Sub hat, nutzt die Vorschau Beispieldaten für `lastFollower`, `lastSub` und `lastGiftedSub`.
- Um die Ausgabe von `console.log` und Fehler zu sehen, klick auf den Pop-out-Button und öffne in diesem Fenster die Entwicklertools.

## Beispiel: Follower-Ziel

Das ist ein kurzes Follower-Ziel. Es nutzt einen Event-Listener, `globalValues` und zwei Nutzervariablen: `follower_goal` (Zahl) und `bar_color` (Farbe).

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

Für eine vollständige Version mit mehr Einstellungen starte ein neues Widget mit der Vorlage **Simple Follower Goal**.

## Tipps

- Zeichne den ersten Zustand aus `globalValues` und ändere ihn dann bei Events. Ein Widget, das auf ein Event wartet, sieht leer aus, bis etwas passiert.
- Gespeicherte Widgets zeigt Test-Buttons nur für Event-Namen, die in deinem JavaScript vorkommen. Schreib den vollen Event-Namen (zum Beispiel `'followEvent'`) in deinen Code, damit Streamer dein Widget testen können.
- Lass den Hintergrund transparent, außer ein Hintergrund gehört zum Design. So liegt das Widget über der Szene.
- Du kannst Builder-Widgets auch mit der KickBot-API verwalten. Siehe die [API-Referenz für Widgets](https://kickbot.com/docs/api/reference/widgets).
