StreamSync Bot — Command & Variable Reference
🍼 ELI5
This is the chat bot: it can reply to !commands, count things (like how many times someone's been timed out), hand out points for watching, and run giveaways — all in Twitch chat, all without you typing anything yourself once it's set up.
Overview
The Chat Bot is Twitch-only and works the same way in the Demo and Pro editions. YouTube and Kick chat (Pro) are not wired into the bot engine — commands, timers, and counters don't respond there, though you can still send a one-off message to those platforms manually or via a trigger action. See Connecting Platforms.
The bot engine connects to Twitch IRC using up to two accounts:
- Bot account — reads all chat, handles
!commands, fires timers, monitors for events - Streamer account (optional) — a separate send-only client so responses appear from the streamer rather than a bot account. If no bot account is connected, the streamer account does both roles.
Commands typed in the app chat panel (Bot tab → Chat) are sent through the same Twitch IRC path as viewer messages, so they trigger command dispatch just like typing in Twitch chat. The local echo shown in the app is added immediately; the IRC echo that comes back from Twitch is deduplicated so no duplicate message appears in the chat view.
In-app Chat Panel
The Chat sub-tab inside Chat Bot shows live chat as the bot sees it and lets you send messages as either account.
Sending messages
Use the account selector at the bottom of the panel to choose whether your message goes out as the Streamer or Bot account, then type and press Enter (or click Send).
- Messages appear immediately in the panel (local echo) and are also pushed to connected overlay chatboxes in real time.
- BTTV, 7TV, FFZ, and Twitch channel emotes typed in the panel are resolved to images in both the overlay and the chat panel.
@mention autocomplete
Type @ followed by a letter to see a dropdown of matching viewers, drawn from the same live viewer list shown in the Viewers sub-tab (mods, VIPs, subs, followers, and lurkers currently in chat). Matching is by display name or Twitch login, whichever the typed letters match.
- Use ↑ / ↓ to move through the suggestions, Enter or Tab to pick one, and Esc to dismiss the dropdown without picking anything.
- You can also click a suggestion with the mouse.
- Picking a suggestion inserts their display name (e.g.
@SomeViewer) in place of what you typed. - Typing a space cancels the dropdown — it only appears while you're actively typing the name after the
@.
Nicknames
Right-click (or click) any username in the chat panel to open a context menu. From there you can:
- Set a nickname — replaces the user's display name everywhere in the panel for the current session. Nicknames are saved to
localStorageand persist across app restarts. - Clear nickname — removes a previously set nickname.
- Timeout or Ban a user directly from the panel.
- View on Twitch — opens their channel in the browser.
Activity Feed (Dashboard)
The Activity Feed on the Dashboard tab shows stream events (follows, subs, raids, redeems, cheers, etc.) collected since the bot connected. The feed:
- Holds up to 100 entries (oldest are dropped when the limit is reached).
- Persists across app restarts — entries are saved to
localStorageand reloaded on next launch so you don't lose the record of events when you close and reopen the app. - Chat messages are intentionally excluded from the feed to keep it focused on stream events.
Commands
Commands are chat-triggered responses. Any message starting with ! is checked against the command list.
Creating a command
Via the app — Bot tab → Commands → Add Command.
Via chat (mod/broadcaster only):
!command add !<name> <response>
!command edit !<name> <new response>
!command delete !<name>
!command enable !<name>
!command disable !<name>Permission levels
| Level | Who can trigger |
|---|---|
everyone | Any viewer |
subscriber | Subscribers + mods + broadcaster |
moderator | Mods + broadcaster |
broadcaster | Broadcaster only |
Cooldown
Set in seconds per command. The same command cannot fire again until the cooldown has elapsed. Cooldowns are shared across all users.
Timers
Timers send a message to chat automatically on an interval.
Via chat (mod/broadcaster only):
!timer add <name> <minutes> <message>
!timer delete <name>
!timer enable <name>
!timer disable <name>Timers also respect a "minimum messages between fires" setting — if chat is quiet the timer won't spam an empty room.
Counters
Counters are named integers you can read and modify from command responses.
Via chat (mod/broadcaster only):
!counter add <name>
!counter delete <name>
!counter set <name> <value>
!counter reset <name>Read in a response: {counter:name}
Modify and read in a response (the counter is updated, and the new value is substituted):
| Syntax | Effect |
|---|---|
{counter:death} | Read current value |
{counter:death++} | Add 1, return new value |
{counter:death--} | Subtract 1, return new value |
{counter:death+1} | Add 1 (explicit) |
{counter:death-1} | Subtract 1 (explicit) |
{counter:death+5} | Add any integer |
{counter:death-5} | Subtract any integer |
Example — death counter:
!counter add death- Add command
deathwith response:💀 Accoustium has died {counter:death++} time(s)!
Every !death in chat increments the counter and announces the new total. Reset anytime with !counter reset death.
Quotes
Quotes are saved sayings or memorable moments from chat. Any viewer can retrieve them; only mods and the broadcaster can add, edit, delete, or import them.
Chat commands
| Command | Who | Effect |
|---|---|---|
!quote | everyone | Post a random quote |
!quote <id> | everyone | Post quote by number |
!quote add <text> | mods + broadcaster | Save a new quote |
!quote del <id> | mods + broadcaster | Delete a quote |
!quote edit <id> <new text> | mods + broadcaster | Update quote text |
The bot response format is: #3: "You can't stop the music." [Just Dance]
Managing quotes in the app
Bot tab → Quotes — add, edit, delete, and search quotes without typing in chat. The Import button opens a file picker that accepts JSON or CSV files.
Importing quotes
Click Bot tab → Quotes → Import to import a file. The importer skips any row where quote is blank and reports how many were added vs. skipped.
JSON format
An array of objects. Only quote is required; game, addedBy, and createdAt are optional and default to empty / current time if omitted.
[
{
"quote": "You can't stop the music.",
"game": "Just Dance",
"addedBy": "ChatMod",
"createdAt": "2024-03-15T21:00:00Z"
},
{
"quote": "gg no re"
}
]CSV format
The first row must be a header row. Column order does not matter — the importer matches by name, not position. Only quote is required.
quote,game,addedBy,createdAt
"You can't stop the music.",Just Dance,ChatMod,2024-03-15T21:00:00Z
gg no re,,,Supported header names: quote, game, addedBy, createdAt.
Note: The CSV parser splits on commas. Cells that contain commas must be wrapped in double quotes (
"like, this"). Other delimiters (semicolons, tabs) are not supported — convert to CSV first.
Variable Reference
Variables are substituted at the moment a command fires.
Message context
| Variable | Value |
|---|---|
{user} | Display name of the user who triggered the command, with @ prefix |
{channel} | Channel name (login, lowercase) |
{count} | Number of times this specific command has been used |
{args} | All arguments after the command name, joined by spaces |
$1 / {1} | First argument |
$2 / {2} | Second argument |
$N / {N} | Nth argument (up to 9) |
Example — !hug @Accoustium with response {user} hugs $1 warmly! → @StreamerName hugs @Accoustium warmly!
Target user (commands with an argument)
If a command's response contains any of these, StreamSync automatically resolves the command's first argument (e.g. @streamer in !so @streamer, stripping a leading @) as a Twitch user via the Helix API before sending the response — no separate action needed, and commands that don't use these run exactly as before with no extra lookup. This is the same automatic resolution Triggers & Actions uses for a Bot Command trigger, so it behaves identically whether the command is a simple Bot Command or a trigger rule.
| Variable | Value |
|---|---|
{targetUser} | Display name of the resolved target user |
{targetUserId} | Twitch user ID of the resolved target user |
{targetUserLogin} | Login name (lowercase handle) of the resolved target user |
{targetGame} | Name of the game/category on the target's channel |
{targetGameId} | Twitch game/category ID |
{targetTitle} | Current title of the target's channel |
All six are empty strings if the argument doesn't match a real Twitch account, or the command was used with no arguments.
Example — !command add !so Shout out to our friend {targetUser}! They were last playing {targetGame}. — then !so @streamer in chat.
Note: because this needs a network round-trip to Twitch, the response arrives a moment after the command is used, not instantly like the other variables above.
Counters
| Variable | Value |
|---|---|
{counter:name} | Current value of counter name |
{counter:name++} | Increment and return new value |
{counter:name--} | Decrement and return new value |
{counter:name+N} | Add N and return new value |
{counter:name-N} | Subtract N and return new value |
Stream state
Stream state variables are populated from Twitch EventSub events and the Helix API. They are available in commands, timer messages, and trigger action parameters. No API call is made at substitution time — values are cached in memory and refreshed automatically.
| Variable | Value | Update source |
|---|---|---|
{viewer_count} | Current viewer count | Helix /streams, every 60 s |
{stream_title} | Current stream title | Helix /streams, every 60 s |
{stream_game} | Current game/category name | Helix /streams, every 60 s |
{uptime} | Elapsed time since stream started (e.g. 2h 14m, or offline) | Computed from Helix started_at |
{follower_count} | Total follower count | Helix /channels/followers, every 5 min |
{sub_count} | Total subscriber count | Helix /subscriptions, every 5 min |
{latest_follower} | Display name of the most recent follower | EventSub follow |
{latest_sub} | Display name of the most recent subscriber | EventSub subscribe / subscribe.message |
{latest_sub_tier} | Tier of the most recent sub (Tier 1, Tier 2, Tier 3) | EventSub subscribe |
{latest_gifter} | Display name of the most recent gift-sub giver | EventSub subscribe.gift |
{latest_gift_count} | Number of subs gifted in that event | EventSub subscribe.gift |
{latest_raider} | Display name of the most recent raider | EventSub raid |
{latest_raid_viewers} | Viewer count they brought | EventSub raid |
{latest_cheerer} | Display name of the most recent cheerer | EventSub cheer |
{latest_cheer_bits} | Bit count from that cheer | EventSub cheer |
Note: "Latest" variables default to empty string until the first matching event arrives in the current session. Helix variables start as
0/ blank until the first poll completes (a few seconds after the bot connects).
Points System
The bot includes an optional viewer points system. Points are awarded automatically to chatters who are active while the stream is live, and can be spent on gambling commands.
Enabling and configuring
Go to Bot → Points to enable the system, set the currency name (e.g. "coins", "gold"), configure the accrual rate (points awarded per interval to active chatters), and the accrual interval.
Viewer commands
| Command | Who | Description |
|---|---|---|
!points | Everyone | Shows your current point balance |
!points @user | Everyone | Shows another viewer's balance |
!top | Everyone | Lists the top 5 point holders |
!slots <amount> | Everyone | Spin the slot machine. Win multiplier depends on matching symbols. Type !slots all to bet everything. |
!roulette <amount> | Everyone | Bet red or black (50/50). Type !roulette all to bet everything. |
!gamble <amount> | Everyone | Flip a coin — win or lose the bet. Type !gamble all to bet everything. |
Moderator commands
| Command | Who | Description |
|---|---|---|
!give <user> <amount> | Mods + broadcaster | Gives amount points to the specified viewer. |
Slot machine payouts
!slots pays out based on symbol matches:
| Result | Outcome |
|---|---|
| Three of a kind | Win × multiplier (🍒 ×2, 🍋 ×3, 🔔 ×5, ⭐ ×8, 💎 ×15, 7️⃣ ×50) |
| Two of a kind | Break even (bet returned) |
| No match | Lose the bet |
Giveaways
The Giveaway feature lets you run a keyword-entry giveaway directly from the bot. Viewers enter by typing a single word in chat; the bot tracks who entered and picks a winner on demand or automatically when a timer runs out.
Running a giveaway
- Go to Bot → Giveaway.
- Fill in the form:
- Entry keyword — viewers must send this exact word (and nothing else) to enter. Case-insensitive (
JOINandjoinare treated the same). - Description — shown in chat when anyone types
!giveaway(or when a timer fires the command). Optional but recommended. - Duration — if set, the giveaway closes automatically after this many minutes and picks a winner. Leave blank to close manually.
- Entry keyword — viewers must send this exact word (and nothing else) to enter. Case-insensitive (
- Click Start Giveaway.
While the giveaway is active the panel shows a live entrant count. When you're ready to pick a winner:
- Click Choose winner (or wait for the timer to fire) — the winner is announced in chat and displayed in the panel.
- Click Redraw to pick a different winner from the same pool.
- Click Reset to clear everything and start fresh.
If you want to stop accepting entries without picking a winner yet, click Close entries first, then Choose winner when ready.
Chat commands
| Command | Who | Effect |
|---|---|---|
!giveaway | Everyone | Announces the giveaway description and entry keyword in chat |
Tip: Create a timer with message
!giveawayto automatically remind viewers about the giveaway on an interval while it runs (e.g. every 5 minutes).
How entry works
A viewer enters by sending a message that is only the keyword — nothing before or after it. Extra words, punctuation attached to the word, or combined phrases do not count.
| Message | Counts? |
|---|---|
join | Yes |
JOIN | Yes (case-insensitive) |
join please | No |
please join | No |
join! | No |
Each viewer can only enter once — duplicate messages from the same account are silently ignored.
Persistence
Giveaway state (active keyword, entrant list, winner) is saved to disk. If the app is closed while a giveaway is running, the state is restored on the next launch. If a timed giveaway's deadline passed while the bot was offline, the winner is drawn automatically as soon as the bot reconnects.
Overlay integration
Every chat message the bot receives is also broadcast over the overlay WebSocket server, so overlay pages receive chat.message events in real time. Command responses sent by the bot are broadcast the same way. See Overlays for the full event payload reference.
Tips
- A command response can contain multiple variables:
Welcome back, {user}! We've died {counter:death} times and have {sub_count} subs watching {stream_game} with {viewer_count} viewers. - Counter mutations happen left-to-right. If you use
{counter:death++}twice in one response, the counter increments twice. - Timers support the same variables as commands (except
{user},{args}, and positional args, which have no meaning without a triggering user). - Commands with
broadcaster-only permission can still be triggered from the app's chat panel regardless of who is logged in. - The app chat panel sends messages as the streamer or bot account depending on which is selected. Either way,
!commandsin the panel are executed by the bot normally — the suppression logic only prevents duplicates in the chat view, not command execution.