# Coming from StreamElements

Import your StreamElements commands as Bloopbot flows, map loyalty, timers and overlays onto Bloopbot, and switch over cleanly.

Updated 24 September 2026

## Before you start

This guide maps what you already built in StreamElements onto the closest thing in Bloopbot. Your commands can come across automatically: see [Import your commands](https://bloopbot.com/docs/coming-from-streamelements#import). A command is a flow, and what you see in OBS is a widget you build in its own editor — **Widgets**, separate from the flow canvas, in the same Bloopbot dashboard.

> **New channels**
>
> If the sign-in button on the Bloopbot homepage reads “Sign-ups are closed right now”, new channels can’t join yet. If you already have a Bloopbot channel, everything below works today; if you don’t, this guide will still be here once sign-ups reopen.

## Commands and permissions

StreamElements’ Custom Commands panel, its user level and its cooldowns become a flow with a trigger and, where you need one, a check node:

| In StreamElements | In Bloopbot | Notes |
| --- | --- | --- |
| A custom command | A flow with a **Chat command** trigger ([create your first chat command](https://bloopbot.com/docs/first-command)) | The trigger’s **Command** field is the word without the prefix; **Also responds to** is the alias list. |
| Permission level: Everyone / Subscriber / VIP / Moderator / Broadcaster | A **Who can trigger** check, **At least** set to the matching level | That is Bloopbot’s full ladder for this check. Moderators and the broadcaster always pass regardless of what you pick. |
| Permission level: Regular | A **Has a role** check, **Roles** left at its default `Regulars` | A different check node from **Who can trigger**: **Has a role** reads People → Regulars (or any other role you name), and the broadcaster and moderators pass it by default too — see [reward viewers and recognise regulars](https://bloopbot.com/docs/loyalty-and-regulars). |
| Global cooldown / user cooldown | A **Cooldown** check with **Whole channel** and/or **Per viewer** durations | Both bots let you set a channel-wide and a per-viewer cooldown on the same command; Bloopbot also lets moderators or you skip it. See [add permissions and cooldowns](https://bloopbot.com/docs/permissions-and-cooldowns). |
| Timers | A flow with an **On a timer** trigger | See [post a recurring chat message](https://bloopbot.com/docs/timers). |
| Spam filters (links, caps, symbols, blacklist/whitelist) | The channel-wide filters on **Moderation** | Settings applied to every message, not a flow you draw — see [set up moderation helpers](https://bloopbot.com/docs/moderation). |
| Loyalty points, earned by watching | Bloopbot loyalty points, configured on **Loyalty**, read with `!points`/`!watchtime`/`!top` | Separate systems and separate balances — a viewer’s StreamElements points do not carry over. See [reward viewers and recognise regulars](https://bloopbot.com/docs/loyalty-and-regulars). |
| The Stream Store (spend loyalty points on a streamer-defined reward) | No catalogue equivalent — build the same shape as a flow, the way Bloopbot’s own `!give` does | Bloopbot has no store record listing redeemable items. What it does have is the same underlying move: a **Read points & watch time** step, a check that the balance covers the cost, then a **Set a variable** step that subtracts `loyalty_balance` — exactly how the built-in `!give` flow spends points. A **Giveaway** with a ticket cost is the closest ready-made version of “spend points for something” — see [run a giveaway in chat](https://bloopbot.com/docs/giveaways). |
| Overlays and alerts (one browser source for everything) | Bloopbot **widgets** — a hosted overlay you design once, added to OBS as its own Browser Source | Alerts are layers on a widget you build; see [add a widget to OBS](https://bloopbot.com/docs/widgets-in-obs) and [show alerts on stream](https://bloopbot.com/docs/alerts). |
| Song requests | The **Song requests** flow pack, playing through your own linked Spotify account | See [let chat request songs](https://bloopbot.com/docs/song-requests). Song requests and hosted widgets may not be available on your channel yet — check [what your plan includes](https://bloopbot.com/docs/what-your-plan-includes). |

## Variables

StreamElements documents `$()` and `${}` as interchangeable — `$(uptime shroud)` and `${uptime shroud}` are the same call — while Bloopbot only ever uses `$(…)`:

| StreamElements | Bloopbot | Notes |
| --- | --- | --- |
| `$(user)` / `${user}` | `$(user)` — a **Chat command** trigger’s “Who typed it” | Same meaning: whoever ran the command. |
| `$(touser)` / `${touser}` | `$(touser)` — “First word, or the viewer” | Also literally named `touser` in Bloopbot. |
| `$(1)` … `$(9)` / `${1}` … `${9}` (positional arguments) | `$(1)` … `$(9)` work the same way in any flow text field; the full remainder is `$(query)` | All nine work — the Starter pack’s own `!deaths +5` counter reads the amount as `$(3)`. Only `$(1)` and `$(2)` appear in the trigger’s own tray and **Insert…** menu; further words you type by hand, or read the whole thing with `$(query)`. |
| `$(count)` / `${count}` / `${getcount}` (per-command counters) | A declared **variable** plus a **Set a variable** action, read back as `$(var.name)` | Declare the variable once on **Variables**, then a **Set a variable** step adds to it — the Starter pack’s own `!deaths` counter is built exactly this way. See [keep a counter with variables](https://bloopbot.com/docs/variables). |
| `$(random.pick 'a' 'b' 'c')` | No direct equivalent | There’s no node that returns a random pick from a written-out list of choices. A **Random chance** check can send different viewers down different branches, but each branch is its own wired-up reply, not one field with a list in it. |
| `$(uptime)` / `${uptime}` | Partial: the Insert… menu’s **Stream** group offers **how long ago** (`$(data.stream.started_at_ago)`, a human string like “3 hours”) and **minutes ago** (`$(data.stream.started_at_ago_minutes)`) | It keeps counting after the stream ends, so pair it with a **Stream status** check if you only want it while live. |
| `$(channel.game)` / `${channel.game}` | Partial: the **Stream info changes** trigger hands on **Category** and **Title** | Only at the moment you change them — there is no token that reads the current category on demand. |

A field that accepts variables shows an **Insert…** menu listing exactly what that step can read, so you don’t have to remember the exact token.

## Import your commands

Bloopbot can read the commands on your channel’s public StreamElements command list and turn each one into a flow for you. You don’t sign in to StreamElements, and nothing changes in StreamElements.

1. Open the importer. It’s step 2 of the **Setup guide**, **Coming from Nightbot or StreamElements?**, and it’s also under **Flows → + New flow → From another bot**. Or follow [bring my StreamElements commands](https://bloopbot.com/admin/import/streamelements) straight from here.
2. Choose **StreamElements**. Bloopbot lists the commands StreamElements shows publicly for the Twitch account you signed in with.
3. Read each row. It shows the command, who could use it, its cooldowns, and its reply as Bloopbot will send it. A warning line means something didn’t carry over exactly.
4. Untick anything you don’t want. Tick **Turn on now** for a command you want answering chat straight away. Everything else arrives paused.
5. Press **Bring these over**. Each command becomes its own flow called `!command (from StreamElements)` on your **Flows** page.

![Step 2 of the Setup guide, Coming from Nightbot or StreamElements?, marked Optional, with From Nightbot and From StreamElements buttons.](https://bloopbot.com/docs/screenshots/setup-import-step.jpg)

_Step 2 of the Setup guide: bring your commands before you pick packs._

![The Bring commands from another bot page listing six Nightbot commands, each ticked to bring over with a Turn on now box: !discord also answering !dc, !deaths counting in the variable deaths\_count from 37 and set to turn on, !lurk, !hug for subscribers and up, !setgame for moderators and up, and !time with a warning that its time token has no Bloopbot equivalent and its Turn on now box greyed out.](https://bloopbot.com/docs/screenshots/bot-import-review.jpg)

_The review, shown here for Nightbot: each row says who could use the command and how often, and a row with a warning can’t be turned on until you’ve fixed it._

What each command becomes:

- The permission level becomes a **Who can trigger** check, or a **Has a role** check for Regular. The global and user cooldowns become a **Cooldown** check on **Whole channel** and **Per viewer**.
- A command set to work only while you’re live, or only while you’re offline, gets a **Stream status** check.
- The aliases carry over as **Also responds to**. A reply sent as a reply or a mention keeps that style in **Chat message**.
- `${user}`, `${sender}`, `${touser}` and `${1}` to `${9}` become their `$(…)` equivalents, and `${1:}` becomes `$(query)`. `${count}` becomes a counter variable named after the command. StreamElements doesn’t publish its counts, so the counter starts at 0. Set the old number on **Variables** if you want to keep it.
- A command switched off in StreamElements is listed as **Switched off there** and isn’t ticked.

Some rows can’t go live straight away. Their **Turn on now** box is greyed out, and the command is brought over paused, as written, for you to finish in the editor:

- a token Bloopbot doesn’t have, such as `${random.pick …}` or `${channel}` (see [Variables](https://bloopbot.com/docs/coming-from-streamelements#variables-map) for what to use instead);
- a command that cost loyalty points, because Bloopbot doesn’t charge for it;
- a command that also answered keywords or a pattern, because Bloopbot answers the command word only;
- a whisper, which Bloopbot posts in chat instead.

The importer doesn’t bring over commands you hid from your public command list, or your timers, spam filters, Regulars list, quotes or loyalty points. Rebuild those as below. A Regular-level command still arrives with its **Has a role** check, so add your regulars on **People → Regulars**.

> **Your plan**
>
> Imported commands are flows like any you make, so they count towards your plan’s flow limit. Your first import is never refused for the limit, however many commands you bring. After that, the review shows how many more your plan has room for. If you tick more than that, nothing is brought over until you untick some. See [what your plan includes](https://bloopbot.com/docs/what-your-plan-includes).

You can run the importer again after you add commands in StreamElements. A command you already brought over shows **Already brought over**, and one a flow here already answers shows **You already have**. Neither is ticked. If you tick a **You already have** row, it arrives paused beside your existing flow, so you can pick which one to keep on.

## Recreate your top commands

Use this for anything the importer couldn’t bring over, or to start from Bloopbot’s own ready-made flows. Do it once your channel is signed in.

1. Open **Flows → Explore packs** and install the **Starter** pack for the everyday commands and stream reactions it covers, including its own `!deaths` counter (mods add to it with `!deaths +`) as a working example of a StreamElements-style tally.
2. For anything Starter doesn’t cover, press **+ New flow → Start blank**, add a **Chat command** trigger, and connect a **Chat message** action with your reply text.
3. Add a **Who can trigger**, **Has a role** or **Cooldown** check in front of the action for anything that had a permission level or a cooldown in StreamElements.

![The Explore packs page: the category filters All, Alerts, Moderation, Music, Community and Utility, then the Starter pack card marked Popular with 11 flows and the Alerts pack card marked New with 7 flows, whose description says it shows your alert designs on your overlay with a thank-you in chat, each with its Use pack button.](https://bloopbot.com/docs/screenshots/flow-templates.jpg)

_Explore packs: install the Starter pack, then add anything it doesn’t already cover._

A worked example — a public `!discord` command with a moderator-only `!setdiscord` to update the link:

1. On **Variables**, declare a text variable named `discord_url` with your current invite link as its starting value.
2. Build a flow: **Chat command** (`discord`) → **Chat message** reading `Join us: $(var.discord_url)`.
3. Build a second flow: **Chat command** (`setdiscord`) → **Who can trigger** (**At least**: moderator) → **Set a variable** (`discord_url`, set to `$(query)`) → **Chat message** reading `Discord link updated.`
4. Save both, then test as below before you rely on them live.

![The flow canvas with a Chat command trigger connected to a Chat message action. Under the trigger, a tray of the values it hands on — Who typed it, After the command, Word 1, Word 2 and a +1 more button; under the Chat message, its Message field with a user badge. The node palette is on the left and Test fire and Save are in the top bar.](https://bloopbot.com/docs/screenshots/flow-canvas.jpg)

_The canvas view of a command flow: a Chat command trigger feeding a Chat message action, with the values the trigger hands on — Who typed it, After the command, Word 1, Word 2 — in the tray underneath._

## Recreate timers and filters

For a StreamElements timer, add an **On a timer** trigger to a new flow and connect it to a **Chat message**; set the interval, or specific days and a time. See [post a recurring chat message](https://bloopbot.com/docs/timers).

For StreamElements’ spam filters, open **Moderation** and configure the equivalent filter directly — it applies to every message and isn’t something you build as a flow. See [set up moderation helpers](https://bloopbot.com/docs/moderation).

## Move your overlay and alerts

StreamElements plays alerts through the same single browser source as the rest of its overlay. In Bloopbot, build a widget with the alert layers you need in the **Widgets** editor, then add its own Browser Source in OBS — [add a widget to OBS](https://bloopbot.com/docs/widgets-in-obs) and [show alerts on stream](https://bloopbot.com/docs/alerts) walk through both. Widgets may not be available on your channel yet — check [what your plan includes](https://bloopbot.com/docs/what-your-plan-includes).

1. Build the new widget in Bloopbot first, with its alert layers configured the way you want them to look.
2. Use **Simulate → Test events** in the editor’s top bar to check an alert plays and looks right, with its “Also play on the live overlay in OBS” box left unticked so nothing reaches a real viewer.
3. Press **Publish**. OBS only ever shows a widget’s last published version — nothing you build reaches OBS until you publish it.
4. Add the widget’s OBS URL as a new Browser Source, sized to your canvas, alongside your existing StreamElements source — don’t replace it yet. An alert layer’s own **Test on stream…** button sends one real test to OBS so you can confirm it, without waiting for a real event.
5. Once you’re happy, remove the StreamElements Browser Source from your scene so only one overlay is answering the same alert.

## Turn off the old bot

For each command, timer or filter you’ve rebuilt, switch off the StreamElements original — in the StreamElements dashboard, not here — once its Bloopbot flow is live and doing the same job. Leaving both running is what causes duplicate replies and, for alerts, two overlays drawing the same event at once.

When you’re ready to retire the StreamElements chatbot entirely, use **Part** in its dashboard’s Chatbot section (or the `!bot part` chat command) to remove it from your Twitch chat, and consider `/unmod`-ing its account in Twitch chat once it has left.

## Check it before you rely on it

Bloopbot draws a clear line between a simulated check and something that actually reaches Twitch or OBS:

- **Test fire**, in the flow editor’s top bar, runs the flow as a dry run and records what would have happened — it does not post to real chat and does not touch a real viewer’s cooldown or points.
- In the widget editor, **Simulate → Test events** plays in the preview only, until you tick “Also play on the live overlay in OBS”; an alert layer’s own **Test on stream…** sends one real test to OBS — either way, OBS only ever shows what you last **Published**.
- A real check means typing the command in your own Twitch chat, or triggering the real event, and watching for the actual reply or alert, exactly once.

## Troubleshooting

- **The importer says StreamElements has no channel for you.** Bloopbot looks for the StreamElements channel of the Twitch account you signed in with. If you used StreamElements on a different Twitch account, its commands can’t be imported here, so rebuild them as above.
- **The importer says the StreamElements channel belongs to a different Twitch account.** A channel with your name on StreamElements is linked to another Twitch account, so Bloopbot won’t read it.
- **A command you had isn’t in the list.** It’s hidden from your public command list in StreamElements. Rebuild it as above, or make it visible in StreamElements and run the importer again.
- **You get two replies, or two alerts.** StreamElements and Bloopbot are both still answering the same command, timer or event. Turn off the one you’re retiring, and for alerts remove the matching OBS Browser Source — see “Turn off the old bot” and “Move your overlay and alerts” above.
- **The command does nothing.** Check the flow is live rather than paused, and that a **Who can trigger**, **Has a role** or **Cooldown** check isn’t quietly stopping it for the account you’re testing with. [Fix a flow or connection](https://bloopbot.com/docs/troubleshooting) walks through the rest.
- **The reply shows `$(var.discord_url)` or `$(user)` literally, instead of the value.** The variable was never declared on **Variables**, or the token is misspelled — check it against the **Insert…** menu on that field rather than retyping it from memory.
- **The reply shows `[count: use $(var.…) — see docs/flows.md §3b]`.** That’s Bloopbot’s deliberate placeholder for a literal `$(count)` or `${count}` left over from StreamElements — there is nothing to count without a declared variable. Replace it with a variable and a **Set a variable** step, as in “Recreate your top commands” above.
- **The overlay is blank in OBS.** An alert layer stays blank until an alert plays on it — use **Simulate → Test events** or an alert layer’s own **Test on stream…**, and confirm you’ve pressed **Publish** and the Browser Source points at the current widget URL. [Fix a flow or connection](https://bloopbot.com/docs/troubleshooting) covers the rest of the OBS checks.
