# Make your chat box react to chat

Put a chat widget in OBS, then pin, badge or hide a message from a flow as it happens.

Updated 23 September 2026

## Before you start

This action draws on a **Chat** layer — the chat box you put in OBS. If you do not have one yet, create a widget on **Widgets** that starts with **Chat** (or add a Chat layer to one you already have) and paste its URL into an OBS **Browser Source** (1920 × 1080, transparent background), following [Add a widget to OBS](https://bloopbot.com/docs/widgets-in-obs).

- A chat box that is actually open. A pin or a badge is only published while a chat widget is connected somewhere; with none, the flow still runs and its run log says **no chat widget is connected**.
- The flow editor: add or open a flow under **Flows**. These are canvas nodes, so switch the flow to **Canvas**.
- For the command examples below, the bot needs moderator access to your channel — the Setup guide’s **Give the bot mod** step. The pin and the badge themselves need no Twitch permission.

None of this is Twitch moderation. A hide changes your chat box only; what does reach Twitch is covered in the [hide walkthrough](https://bloopbot.com/docs/chat-box#hide) and in [moderation helpers](https://bloopbot.com/docs/moderation).

## Where the action lives

In a flow, open **Canvas**, then **Browse the library** and search — or type “pin”, “badge” or “hide” into **Add a node**. One node does all three: **Pin, badge or hide chat**, in the **Overlay** group, beside **Show alert**, **Play media** and **Alert queue**, because it draws on an overlay rather than post to chat. Add it once, then pick the choice you want in its **Do** setting.

| Choice in Do | What it does |
| --- | --- |
| **Pin a message on the chat box** | Keeps one message on the screen and highlighted until you unpin it |
| **Badge a message** | Draws a short text badge beside one message |
| **Hide a message from the chat box** | Takes one message off the chat box |

Whichever choice you pick, the node takes the flow’s **next** path and does exactly one thing. It has no message-id field: a Twitch message id is not something you can type, and no `$(…)` token resolves to one, so the action targets the message the run itself is about — the next section. Changing the choice later keeps whatever you already filled in.

![The node library with “chat box” typed into the search field: no triggers or conditions match, and the Then… column shows one action, Pin, badge or hide chat.](https://bloopbot.com/docs/screenshots/chat-node-library.jpg)

_Searching the library for “chat box” finds the one node:  in the  column._

## Which message the action acts on

Every choice reads the same rule, in this order:

1. The message the trigger replied to, when it replied to one. A moderator replies to a viewer’s message and runs `!pin`: the pin lands on the viewer’s message, not on the command.
2. Otherwise the message the trigger event itself carries — a keyword, any chat message, or the **moderation-action** trigger.
3. Otherwise the message that woke the run.

> **The moderation-action trigger carries no reply**
>
> A moderation-action event holds the message the filter acted on and no reply information at all, so the first rule above can never apply to it: a filter flow using this action always targets the message the filter is holding.

> **Delete the message is a different action**
>
> Do not swap **Hide a message from the chat box** for **Delete the message**, and expect them to do the same thing. Delete removes a message in Twitch for everyone (the bot must be a moderator); Hide takes it off your chat box only. Their targets differ on a reply-driven run too: Delete removes the moderator’s own command message, while the chat-box action — pinning, badging or hiding — acts on the message it replied to. The two sit next to each other in the library, so pick the one you mean.

## Pin a message a moderator asked for

A worked example: a `!pin` command a moderator runs as a reply.

1. Open **Flows → Explore packs** and install the **Simple command** template, or open any flow that already has a **Chat command** trigger. A reply drives it either way.
2. Set **Command** to `pin` and **Prefix** to `!`, then switch the flow to **Canvas**. Delete the template’s **Chat message** action if you do not want the bot to answer.
3. Search the node library for **Pin, badge or hide chat** and add it, then set its **Do** field to **Pin a message on the chat box**. Leave **Pin it** on so the node pins; turn it off and the same node unpins instead.
4. Add **Who can trigger** between the trigger and the pin, set its **At least** field to moderators, and connect the passing path to the pin.
5. Press **Save**.
6. Have a moderator reply to a viewer’s message in Twitch chat with `!pin`.

Expected result: that viewer’s message stays on the chat box while new messages arrive — a pin survives both the **Messages on screen** limit and a message lifetime — and the widget draws it highlighted in your theme’s accent colour, so it stands out from the messages around it. One chat box keeps at most three pinned messages, so a fourth pin releases the oldest. Run the flow again with **Pin it** off to take the pin away.

![A Chat command trigger connected to the Pin, badge or hide chat action on the flow canvas, beside its inspector: Do is set to Pin a message on the chat box and the Pin it switch is on, reading “Turn this off to take the pin off the message instead.”](https://bloopbot.com/docs/screenshots/chat-pin-node.jpg)

_The chat-box action on the canvas with the pin choice in use, and  on in the inspector._

> **Test fire is a dry run**
>
> Test fire records **would pin the message on the chat box** in the run log and changes nothing in OBS or Twitch. Only a real trigger — a moderator actually typing `!pin` — reaches your overlay.

## Badge a message

A badge is a short piece of text drawn just before the message. Two common uses: a loyalty rank on every message, and a marker for a viewer’s first message.

1. Add **Pin, badge or hide chat** from the **Overlay** group, then set its **Do** field to **Badge a message**. Run it on a flow that gets chat — a chat-command trigger, **When chat mentions**, or the **Any chat message** trigger.
2. In **Badge**, write what should be shown, for example `Rank $(rank)`. Variables work here exactly as they do in a chat message; the editor’s **Insert…** menu offers loyalty values such as `$(rank)`.
3. Leave **Only the viewer’s first message** off for a badge on every message.
4. Save, then type anything in your own chat to see it.

To mark first-time chatters instead, turn **Only the viewer’s first message** on: the badge is drawn only when the message is that viewer’s first in your channel, and nobody else gets one.

Expected result: the badge appears beside the message within about a second. It is text — at most 24 characters, never a link and never an image — and badging the same message twice replaces the badge instead of adding a second one.

![The Pin, badge or hide chat action selected on the flow canvas, with Do set to Badge a message, the Badge field reading Rank $(rank), a rank badge on the card’s Badge field, and the Only the viewer’s first message switch off.](https://bloopbot.com/docs/screenshots/chat-badge-node.jpg)

_A rank badge:  in the  field, with the first-message switch below it._

## Hide a message your flow decided against

Set the chat-box action’s **Do** to **Hide a message from the chat box** when your own flow has decided a message should not be on your overlay — an AI moderation step flagged it, a keyword matched, or a rule of yours fired. It takes the message off the chat box at once, and a chat widget that connects later is never handed it.

1. Build the flow that makes the decision. The **AI chat moderation — delete and warn** template is one ready-made choice; a chat command or a keyword trigger is a simpler one.
2. On the branch that means “keep this off the box”, add **Pin, badge or hide chat** from the **Overlay** group and set its **Do** to **Hide a message from the chat box**.
3. There is nothing else to set for a hide — leave the other fields alone — so connect it and press **Save**.
4. Let a real message take that path.

Expected result: the message disappears from the chat box immediately. The run log reads **hidden**, or **hidden (no chat widget is connected)** when no widget is open — the removal is recorded either way, so a widget that connects afterwards does not draw the message.

> **A hide is not a Twitch delete**
>
> It changes only what your chat box shows: the message stays in Twitch chat and in every viewer’s own client, and nobody is timed out or banned. If the message should go from Twitch as well, use **Delete the message** (the bot must be a moderator) or the moderation actions in [moderation helpers](https://bloopbot.com/docs/moderation) — and remember Delete targets the message the run holds, not the one a reply answered.

## Check it works

On screen, the change lands within about a second. If it does not, start with the flow’s **Run log**; its detail line says exactly what happened:

| Run-log detail | What it means |
| --- | --- |
| `pinned` / `unpinned` | The instruction reached the chat box |
| `badged with "Rank 3"` | The instruction reached the chat box |
| `hidden` | The removal was recorded and sent to the chat box |
| `no chat widget is connected` | No chat box is open anywhere; a pin or a badge was not sent |
| `hidden (no chat widget is connected)` | Nothing is open, but the removal was still recorded |
| `no message to pin` / `to badge` / `to hide` | The trigger carries no message — a timer, a remote trigger, a reward redemption |
| `the label was empty` | The badge’s text expanded to nothing, such as `$(rank)` with no loyalty configured |

**Test fire** is simulated: it records **would pin…**, **would badge…** or **would hide…** and never reaches OBS or Twitch. The chat box’s own editor has scripted tests that do reach the canvas: open **Simulate**, the arrow beside **Live preview** in the editor’s top bar, and use **Test a pin**, **Test a badge** and **Test a hide**. Each draws a sample message and then the instruction that acts on it, with the option to send the same sequence to OBS so you can confirm the connected Browser Source picks it up.

![The Simulate popover open over a chat overlay’s canvas: Test events offers Test chat, Test a delete, Test a clear, Test a pin, Test a badge and Test a hide, with the “Also play on the live overlay in OBS — viewers will see it” box unticked, then Sample values with Send to OBS…; below it the canvas draws two sample messages, one badged, with the chat layer selected.](https://bloopbot.com/docs/screenshots/chat-widget-tests.jpg)

_Simulate on a chat box. ,  and  each draw a sample message and then act on it; leave the OBS box unticked to keep the test on the canvas._

- Nothing changes and the log says **no chat widget is connected**: no chat box is open anywhere. Open the OBS scene with your chat widget, or stop hiding it, and try again — no flow is broken.
- A pin or badge draws nothing: the message was already off the screen, pushed out by newer messages or never drawn. The bot cannot see inside your chat box, so there is nothing to act on — raise **Messages on screen** in the chat widget’s settings, or act sooner.
- A hide did nothing in Twitch: correct. Hide is your chat box only; use **Delete the message** for Twitch.
- Two different results from one chat line: check for another flow listening to the same command or event.

## What these actions do not do

- A pin and a badge are screen state. A chat widget that reconnects starts unpinned and unbadged, and the flow sets them again the next time it runs — nothing about them is stored in Bloopbot.
- A chat box keeps at most three pins. A fourth releases the oldest, and a pinned message is exempt from **Messages on screen** and from a message lifetime while it is pinned.
- The target is always the message a run is about. A trigger with no message in hand — a timer, a remote button you set up, a reward redemption — does nothing and says so in the run log rather than failing.
- A hide removes the one message the run holds, not every message from that viewer: there is no per-viewer “hide this person” switch and no undo.
- Nothing in this guide reaches Twitch. Pinning, badging and hiding never delete, time out or ban anyone.
- These three choices work on a chat box you created in Bloopbot. A chat box you built yourself as an HTML file cannot receive them.
