Chatters module
The Chatters module is StreamerCatalyst’s chat bot. It answers custom commands, posts scheduled and keyword-triggered auto-chat messages, keeps quotes and counters, runs a chat countdown timer, and exposes a public API that lets external bots (Nightbot, StreamElements, Fossabot) pick random chatters or run FMK polls.
Available on the Free tier and above. See Module access by tier.
At a glance
| Capability | What it does |
|---|---|
| Custom commands | !commands with template variables, permission levels, cooldowns, and aliases |
| Built-in commands | !uptime, !game, !title, !followage, !hypecheck, !so, !timer, !quote, mod tools, and more |
| Auto-chats | Scheduled or keyword-triggered messages with chat/reply/announcement delivery |
| Quotes | Indexed community quotes managed from chat or the dashboard |
| Counters | Named counters usable in command templates, with an optional bits/gift auto-reduce |
| Regulars | A trusted-viewer list that unlocks the regular command permission level |
| Bot identity | Choose who speaks: your account, the shared @StreamerCatalyst bot, or your own bot |
| Import | Bring a StreamElements account across with a JWT (commands, timers, quotes), or paste commands from StreamElements, Nightbot, or Fossabot with variable translation |
| Tip announcements | A templated chat shout-out whenever a tip settles in the Tipping module |
| Bot API | random / fmk / chatters endpoints for external bots, filterable by sub/VIP/mod/follower |
| Public commands page | A shareable page listing your enabled commands |
Bot identity — who sends chat
Every message the bot sends uses your channel’s bot identity, chosen in Chatters → Bot Setup:
- Broadcaster — messages come from your own account (the default, and the fallback whenever a bot token is missing).
- Shared bot — the global @StreamerCatalyst account.
- Custom bot — a dedicated bot account you own; you authorize it once via a Twitch login from the Bot Setup page.
Whichever account sends chat, its messages show Twitch’s verified bot badge once that account has been authorized with the user:bot permission. Bot Setup flags when the badge isn’t active yet (for the shared or a custom bot) and prompts you to re-authorize.
During a Stream Together (Shared Chat) session the bot posts only in your own chat — its replies are not mirrored into your co-streamers’ channels. Announcements are scoped the same way, as long as the account sending them is the one you granted announcement permission to; if we have to fall back to your own account’s login for a send, that one message is mirrored to the whole session.
The bot ignores its own messages, so commands can’t trigger themselves.
Custom commands
Create commands on Chatters → Commands:
| Field | Details |
|---|---|
| Trigger | Starts with !; letters, numbers, _, -; up to 30 characters |
| Response | Up to 500 characters, with template variables |
| Permission | everyone (default), regular, follower, sub, vip, mod, or broadcaster |
| Cooldowns | Global and per-user, 0 – 86,400 seconds each |
| Mode | Plain text or /me action styling |
| Hidden from public list | Excludes the command from your public commands page |
Responses support template variables — $(user), $(touser), positional args, $(random), $(counter …), $(count) (how many times the command has run), and more. See Template variables & built-ins for the full reference, and test any command with the Test button before saving.
The broadcaster bypasses all permission and cooldown checks. follower checks are live against Twitch; regular checks your regulars list.
AI-generated responses — describe what the command should say (plus an optional style: funny, informative, hype, chill) and the AI drafts the trigger, response, permission, and cooldown for you to review. Limited to 10 generations per hour.
Built-in utility commands
Built-ins can be enabled, disabled, and (for most) aliased per channel on Chatters → Utility Cmds:
| Command | What it does |
|---|---|
!uptime | How long the stream has been live |
!game | Shows the current category; mods can change it |
!title | Shows the stream title; permitted users can set it |
!followage | How long the caller has been following |
!accountage | How old a Twitch account is — !accountage for the caller, !accountage @someone for anyone else |
!watchtime | How long a viewer has watched this channel — !watchtime for the caller, !watchtime @someone for anyone else |
!hypecheck | Time since the last Hype Train and when the next one can start |
!commands | Links to the public commands page |
!so | Shouts out a user with a customizable message — optionally firing a native Twitch shoutout too, queued while Twitch’s ~2-minute cooldown is active |
!soq | Shows the native shoutout queue; mods can remove an entry or clear it |
!timer | Starts a chat countdown timer (see below) |
!addcom / !editcom / !delcom | Mods create, edit, or delete custom commands from chat |
!cooldown | Mods set a command cooldown from chat |
How !watchtime is counted. Twitch publishes no watch-time API, so the bot
measures presence instead: every few minutes while you are live it reads your
chatter list and credits everyone on it with the elapsed time. Three consequences
worth knowing before you put the number on screen:
- It starts at zero. There is nothing to backfill from, so watch time begins
accumulating the first time you stream after enabling Chatters. Until then
!watchtimesays so rather than answering0. - It counts viewers whose chat is connected, which is what Twitch’s chatter list reports. Someone watching in an embed or with chat closed is invisible to it, so the figure is a floor, not an exact total.
- It rounds to the poll interval. A viewer present at two consecutive checks is credited for the whole gap; one who drops in and out between them is credited nothing.
While you are live the reply also shows the current session’s time in parentheses; that part resets when the stream starts.
!hypecheck cooldown — Twitch does not expose your channel’s Hype Train
cooldown setting through any API, so set it with the 1–8 hour slider under the
!hypecheck row on the Utility page. It is only a fallback: when a Hype Train
ends, Twitch’s own event tells us the exact instant the next one can start, and
that value wins. Once a train has ended, the page shows the cooldown Twitch
reported so you can tell whether the slider is stale.
Changing the category or title needs one more Twitch permission. Reading
them works out of the box, but !game <category> and !title <text> write
through Twitch’s Modify Channel Information API, which only accepts the
channel:manage:broadcast grant. It is an on-demand scope, so it is not part of
sign-in: press Save on Chatters → Commands → Utility (or the Grant
button on that page) and Twitch will ask for it. Only the broadcaster can grant
it — a moderator re-authorizing would grant it on their own account. Until then
both commands answer in chat with where to go.
!title write access is configurable: the broadcaster always can; grant mods and/or VIPs via role toggles, or grant specific users (optionally time-limited) with title grants on the Utility page.
!so message is editable on the Utility page — set separate templates for when the shouted-out channel has a game vs when it doesn’t (leave blank to use the built-in default), and toggle whether !so also fires Twitch’s native shoutout.
Shoutout queue
Twitch accepts only one native shoutout every ~2 minutes, so a second !so
inside that window used to be rejected and silently lost. With Queue native
shoutouts on (the default), the native shoutout is queued instead and fires
automatically as the cooldown clears. !so and modomation’s native
auto-shoutouts share one queue per channel, so a raid-and-shoutout burst lines
up in order instead of competing.
Settings live in the !so — Shoutout Settings card on Chatters → Utility
Cmds: turn the queue on or off, set the queue size (1–25, default 10), and
optionally announce in chat when each queued shoutout fires. Below it, the
Shoutout queue card lists what’s pending — position, who’s being shouted
out, whether it came from !so or an auto-shoutout, and roughly how long until
it goes out — with a Remove button per entry and Clear queue.
From chat: !soq lists the queue for anyone, !soq remove <user> drops one
entry, and !soq clear empties it (both mod/broadcaster only).
Queued entries expire after 30 minutes, a target Twitch already shouted out in the last hour is skipped, and the queue holds while you’re offline — Twitch only accepts native shoutouts while the channel is live.
Chat timer
!timer 5m Ad break starts a countdown (formats like 5m, 1h30m, 1:30:00, or plain seconds; up to 24 hours; label optional). The bot announces remaining time at sensible marks (only marks shorter than half the duration) and posts ”⏰ Time’s up!” when it completes. One timer runs at a time per channel; mods and the broadcaster start/stop it, anyone can query it.
Auto-chats
Chatters → Auto Chats posts messages automatically. Two trigger types:
- Schedule — fires every N minutes (default 30, minimum 1), optionally only when live, and optionally only when at least N distinct viewers chatted in the last hour (min chat activity), so reminders don’t fire into an empty chat.
- Keyword — fires when a chat message matches one of your keywords (
exact wordorsubstring, optionally case-sensitive), with a per-auto-chat cooldown (default 300 seconds).
Both trigger types share the same conditions: only when live, and an optional stream category filter — only in the categories you list, or never in them. Matching is on the Twitch category itself, so renames don’t break a filter. Leave the list empty to fire in any category. If the category can’t be determined (Twitch is unreachable, or we haven’t seen a category change since setup), an only in filter holds the message rather than posting into the wrong category. Your category stays set while you’re offline, so pair a category filter with only when live if you only want it during a stream.
Each auto-chat rotates through its message list round-robin and delivers as a plain chat message, a reply (keyword only), or a colored Twitch announcement.
Saving an auto-chat in announcement mode sends you to Twitch once to grant the announcement permission — Twitch checks it on the account doing the posting, so an announcement can’t go out until you’ve approved it. If you send chat through the shared or your own bot account, that account also has to be a moderator in your channel to announce; when it isn’t, the announcement is posted from your own account instead of being dropped. Instead of fixed text, an auto-chat can mirror a custom command’s response — live (re-read on every fire) or as a snapshot you re-sync manually; deleting the linked command disables the auto-chat rather than posting stale text.
Auto-chat limits are tier-based: none on Free, 3 on Affiliate, unlimited on Partner and above. If your tier drops, surplus auto-chats are disabled automatically (oldest kept).
Quotes
Store memorable moments as numbered quotes (up to 400 characters; the current game and date are captured automatically):
| Command | Who |
|---|---|
!quote / !quote 42 (or !quote #42) | Anyone — random quote, or quote #42 |
!addquote <text> | Mods and the broadcaster |
!editquote <number> <text> / !delquote <number> | Broadcaster; mods only if Mods can edit/delete quotes is on |
Quote numbers are your channel’s own. Your oldest quote is #1 and they count up to your newest, and what other channels have changes nothing. Deleting one leaves its number empty rather than shuffling everything above it down, so the quotes you keep never move.
The highest number is the one exception: delete your newest quote and the next quote you add takes its number, and a channel that deletes every quote starts again at #1. Nothing below the top is ever handed out twice.
The date the bot prints is the day the quote was added in your channel’s timezone (Settings → Time zone), so a quote added late in the evening is dated that evening and not the next morning. Leave the timezone on UTC and the date is UTC’s, as it always was.
StreamElements’ spelling works too, with the same permissions: !quote add <text>, !quote edit <number> <text>, !quote del <number> (delete / remove also accepted).
Quotes can also be managed (and the feature toggled) on Chatters → Community → Quotes, where every quote’s number is listed in the first column. The captured game can be corrected there too — in chat, !editquote still only changes the text.
Counters
Named counters (hydrate, deaths, …) are read and changed from command templates with $(counter NAME add|sub|set N) — per-viewer by default, or channel-wide with of channel — and support in-chat leaderboards (top). Manage stored values on Chatters → Counters.
Counter auto-reduce (configured on the Commands tab) automatically subtracts from a chosen counter when bits are cheered or subs are gifted — e.g. every 100 bits reduces a “timeout jar” — floored at zero, with an optional templated chat announcement.
Tip announcements
When a tip settles in the Tipping module, Chatters posts a shout-out in your chat. It’s on by default and configured on Chatters → Tip Announcements with a single template (up to 300 characters):
| Variable | Renders |
|---|---|
$(name) | The tipper’s Twitch name, or “Anonymous” |
$(amount) | The tip amount, formatted in your tip currency (“$25.00”) |
$(message) | The tipper’s message, if they left one |
The default is $(name) just tipped $(amount)! $(message). Leave the box blank to use it.
A tip whose message is still waiting for approval is announced without the message text, so nothing unreviewed reaches chat. Announcements are deduplicated, need the Chatters module enabled (it’s the bot doing the talking), and are never retracted if a tip is later refunded.
Wheelspin trigger
Chatters is what listens for the Wheelspin widget’s trigger: the configured chat command (default !spin, broadcaster or broadcaster + mods) and the bits / gifted-sub / tip thresholds you set on the widget. The wheel itself, its items, and the winner announcement are configured in Widgets → Wheelspin — event triggers fire even with the Chatters bot switched off, but the chat command needs it enabled.
Regulars
Maintain a list of trusted viewers (managed on the Commands tab, added by Twitch username). Regulars unlock the regular command permission level — a tier between everyone and follower for commands you want semi-restricted.
Chat activity leaderboard
Every viewer’s message count is tracked per stream, per day (90-day history), and across recent windows, powering the Top Chatters leaderboard (surfaced under Numbers → Top Chatters, with Stream/Today/7D/30D/90D ranges).
Import from other bots
Chatters → Import has two ways in. StreamElements account connects to StreamElements directly and brings your commands, timers and quotes across in one go. Paste commands takes a block of text copied out of any of the three supported bots. If you are moving from StreamElements, use the account import — it carries settings that copying cannot.
Import a StreamElements account
Paste your StreamElements JWT and StreamerCatalyst reads your account directly, so everything behind each command comes with it:
| What comes across | Notes |
|---|---|
| Custom commands | Response, cooldowns, who can run it, aliases, and whether it was enabled |
| Timers | Imported as Auto Chats — every message, the interval in minutes, the chat-lines threshold, and the category filter |
| Quotes | Text, the original date and time, and whoever StreamElements recorded as adding it (plus its category, when it kept one) — blank rather than guessed at when it sent none |
Up to 200 commands, 100 timers and 500 quotes per import, with up to 10 aliases per command and 20 messages per timer — anything past those is reported on the row rather than dropped quietly.
One batch per token. Once you press Import the reviewed batch is spent; to bring more across, press Start over and paste a fresh JWT. That is deliberate — timers have no duplicate check, so a second press would create every one of them again.
Finding your JWT. In StreamElements, open Account → Channels, click Show secrets, and copy the JWT Token.
Moderating for someone else? You do not need the broadcaster’s token. If you are a Lead Mod here and they have added you as an editor on their StreamElements account, your own JWT works. Either way the import only ever reads the channel you are signed in to and writes to that same channel; it can never pull one channel’s setup into another.
If it cannot find the channel, enter its StreamElements ID. There is an optional field under the JWT box. Leave it blank first — most channels are found automatically. Fill it in when they are not, which happens because StreamElements usernames are not unique across Twitch and YouTube, so looking a channel up by name can land on an unrelated account.
If you are moderating for someone else, expect to need it — the field opens with the steps already showing.
Finding the ID is fiddly, and it is not in the address bar; StreamElements does not display it anywhere. It only appears in the requests their dashboard makes:
- Open StreamElements and switch to the channel you are importing.
- Press F12 for your browser’s developer tools.
- Go to the Network tab and type
api.streamelements.comin its filter box. - Click around the dashboard — the bot or commands page will do — so some requests appear.
- Right-click any request, copy its URL, and paste the whole thing into the field.
Paste the entire URL; StreamerCatalyst pulls the ID out of it. If that is more than you want to do, the broadcaster’s own JWT works with no ID at all.
The ID only says which channel to read. The import still refuses unless that channel is the one you are signed in to.
StreamElements editor access is not the same as Twitch editor or moderator access. They are separate systems: being a mod or editor on someone’s Twitch channel gives you nothing in StreamElements. The broadcaster has to add you explicitly, on their StreamElements account, under Account → Channels — as Editor or Full Control.
Two different errors, two different fixes:
- “is not a manager of this channel” — your token works and we found the channel, but StreamElements says you have no grant on it. Ask the broadcaster to add you, or use their JWT.
- “could not find this Twitch channel on StreamElements by name” — enter its StreamElements channel ID, as above. (The broadcaster’s own JWT also works, and needs no ID.)
- “that StreamElements channel ID is not this Twitch channel” — the ID resolved, but to a different channel. Check you copied it while managing the right one.
About that token. It is used for one request and then discarded — StreamerCatalyst never saves it, and you are never asked for it twice. Treat it like a password until you have imported: it grants full access to your StreamElements account, so do not paste it anywhere else, and you can reset it in StreamElements afterwards if you would rather not leave it live.
What does not come across, and why. Nothing is guessed at. Each of these is reported on the row it affects, so you know exactly what to re-add:
- Loyalty-point costs. There is no points cost on a command here, so a command that cost points is imported free to run.
- Regex and keyword triggers. The command imports under its normal
!name. Keyword triggers are better rebuilt as a keyword Auto Chat. - Per-timer title filters. There is no title filter on an Auto Chat, so a timer limited to titles containing a word is imported without that limit, and the words are named on the row.
- Live-only and offline-only settings on commands. There is no live/offline split on a command here, so it is imported to run at all times rather than switched off.
- Quote numbers, authors and games. Quote numbers are assigned fresh — oldest first, continuing after any quotes you already had — so
!quote 4will not be the same quote it was in StreamElements. (Because they continue from what you have, importing an old backlog into a channel that already has quotes numbers the older ones above the newer ones; importing into a fresh channel numbers everything in order.) StreamElements does not record who added a quote or the game it was from, so both are left blank instead of being filled in with something untrue.
Category filters come across. A timer limited to certain categories is looked up against Twitch, so the Auto Chat arrives with the same filter already set. If Twitch does not recognise one of them, the filter is left off entirely and the row says which — an Auto Chat filter is an allow-list, so importing part of one would silently stop the timer posting in the category that went missing.
Permissions map by name, not by rank. StreamElements orders Subscriber below Regular and StreamerCatalyst does not, so the import matches the label — a sub-only command stays sub-only. Super Moderator becomes Mods, since it is a moderator with extra StreamElements-side powers rather than a rank above one.
Re-importing is safe. Commands and timers you already have are marked already here and default to skip, so topping up after adding a few new commands will not overwrite ones you have since tuned. If you do choose to import over an existing command, its response is refreshed and its cooldown and permission are left alone.
Paste commands
The paste importer ingests commands copied from Fossabot, Nightbot, or StreamElements. Variables are translated to StreamerCatalyst syntax where an equivalent exists; anything untranslatable is left exactly as you pasted it and flagged as a warning, so you can find and fix it. A preview step shows conflicts with existing commands — resolve each by importing, skipping, or renaming — and up to 200 commands import per batch.
How the source bot is detected. All three bots write variables as $(name …) (StreamElements also accepts ${name …}), so the brackets don’t identify anything — the variable names do. The importer reads the whole paste, weighs every name that only one of the three defines ($(rngphrase) is Fossabot, $(userlevel) is Nightbot, $(pointsname) is StreamElements), and applies the winner to every line, including the many commands that are plain text with no variables at all. The preview names what it detected; if it guesses wrong, pick the right bot from the Source bot dropdown and the paste is re-translated.
A few translations change more than the brackets:
| From | Becomes | Why |
|---|---|---|
$(sender) | $(user) | Same meaning, different spelling |
$(randint 1 100) | $(random 1-100) | One range argument instead of two bounds |
$(chatters.random) | $(randomchatter) | Same live-chatter draw, and repeats in one response still name different people |
$(count.increment shots) | $(counter shots add 1 of channel) | Fossabot’s custom counters are channel-wide; StreamerCatalyst counters default to per-viewer |
$(count.increment lips-on) | $(counter lips_on add 1 of channel) | Counter names allow letters, numbers and _ only — the rename is reported |
$(rngphrase a,b,c) | $(randompick a|b|c) | Same random pick, StreamerCatalyst’s spelling |
${random.pick 'a b' 'c d'} | $(randompick 'a b' 'c d') | Same grammar — quoted or bare options, whitespace-separated — so the list carries across untouched |
${random.1-26} | $(random 1-26) | Same range; StreamerCatalyst takes the bounds as an argument rather than glued to the name |
${random.number 1-100} | $(random 1-100) | Same range, whether the bounds were written with a hyphen or a space |
${random} | $(random 1-100) | StreamElements’ bare $(random) is documented as 1–100; StreamerCatalyst has no default range, so it is written out |
${random.chatter} | $(randomchatter) | Same live-chatter draw, and repeats in one response still name different people |
$(channel.followers) | $(followers) | The channel’s follower count, from either bot |
$(channel.subs) / $(channel.subscribers) | $(subs) | The channel’s subscriber count |
$(channel.subpoints) | $(subpoints) | The channel’s sub points |
${channel.game} / ${channel.title} | $(game) / $(title) | Same stream fields, StreamerCatalyst’s spelling |
${customapi.URL} | $(urlfetch URL) | Same fetch, StreamerCatalyst’s spelling |
One difference worth knowing about the counts: $(followers), $(subs) and $(subpoints) answer [followers: unavailable] and the like when Twitch cannot be reached, where the old bots print 0. A 0 in chat is a claim about your channel, so StreamerCatalyst says it does not know instead.
Things with no equivalent — Fossabot’s $(chatters.count), Nightbot’s $(userlevel) and its $(twitch … "{{game}}") format strings, and StreamElements’ cross-channel $(channel.game somestreamer) — are listed in the row’s warnings and left untouched rather than silently dropped.
Imported commands start throttled. A paste carries no cooldown settings, and thirty wide-open commands arriving at once is how an import turns into a chat flood — so each newly created command gets a 5-second channel cooldown and a 15-second per-viewer cooldown. Change them any time under Chatters → Commands, or in chat with !cooldown !name global:30 user:10. Re-importing over a command you already tuned refreshes its response and leaves its cooldown alone.
Bot API
External bots call plain-text endpoints on https://chatters.streamercatalyst.com with your API key (a 64-character hex key created automatically at first login; reveal or regenerate it under Chatters → API Key):
/api/random— one or more random chatters (n= 1–10), with an optionalformattemplate./api/fmk— three random chatters for an FMK poll./api/chatters— the full current chatter list (plain or JSON).
All three accept a comma-separated filter: sub, not_sub, tier1/tier2/tier3 (exact tier), vip, mod, follower, not_follower. The endpoints read Twitch’s live chatter list, so the stream must be live. For setup and URL formats per bot, see Bot integration.
Public commands page
Each channel gets a public, no-login page at https://chatters.streamercatalyst.com/c/<channel-login>/commands listing enabled built-in and custom commands (minus any marked hidden). Toggle it on the Utility page; !commands links to it.
Chat behavior and safety
- Bot messages are capped at 500 characters and rate-limited to 20 per minute per channel.
- Incoming chat events are deduplicated for 24 hours, so redeliveries never double-fire commands.
$(urlfetch)-style remote calls in templates are HTTPS-only, timeout-limited, and size-capped, so a slow external API can’t stall chat.
Looking for giveaways? Those run in the Events module.
Configuration
Chatters in the dashboard sidebar: Overview (the bot kill switch — turn it off and the bot stops responding, without touching your plan), Commands (commands, regulars, counter auto-reduce, AI generate), Bot Setup (EventSub, bot identity, bot-API command aliases and default filter), Auto Chats, Quotes, Counters, Utility Cmds, Tip Announcements, API Key, Import, and Advanced (expression tester and template reference).
Regular mods have read access plus day-to-day command work: adding, editing, enabling and deleting custom commands and Auto Chats, AI Generate, and the paste importer. Settings and counters need a Lead Mod or the broadcaster, as does the StreamElements import; the API key and bot identity are the broadcaster’s alone.
Mods can edit/delete quotes (on the Quotes tab) widens !editquote and !delquote in chat. It does not change the Quotes tab itself — editing a quote in the dashboard still needs a Lead Mod or the broadcaster whichever way that switch is set.
Commands & variables reference
See Commands and Template variables & built-ins for the generated full reference.
API and endpoint reference
See Chatters — API endpoints for the full list of HTTP endpoints.
Auth reference
See Chatters — Authentication & permissions for the OAuth scopes this module uses and the EventSub subscriptions it registers.
Share Feedback
Need help or want to chat? Join our Discord to get support, report bugs, and talk with other streamers.▸ What we're sending
| Module | — |
| Page | — |
| Browser | — |
| Screen | — |
| Channel | anonymous |
| Submitted | — |