# Coming from Nightbot

Import your Nightbot commands as Bloopbot flows, map the rest of Nightbot onto Bloopbot, and switch over without duplicate replies.

Updated 24 September 2026

## Before you start

This guide maps what you already built in Nightbot onto the closest thing in Bloopbot, so you are not starting from a blank page. Your commands can come across automatically: see [Import your commands](https://bloopbot.com/docs/coming-from-nightbot#import). Everything in Bloopbot is a flow — a trigger, optional checks and one or more actions you draw on a canvas — so “add a command” and “add a filter” both mean building or installing a small flow rather than typing one line into a settings box.

> **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

Nightbot’s `!commands add`, its `-ul=` userlevel and its `-cd=` cooldown become a trigger and, where you need one, a check node in front of your reply:

| In Nightbot | In Bloopbot | Notes |
| --- | --- | --- |
| A custom command (`!commands add !name reply`) | A flow with a **Chat command** trigger ([create your first chat command](https://bloopbot.com/docs/first-command)) | The trigger’s **Command** field holds the word without the prefix, **Prefix** holds the character before it (`!` by default), and **Also responds to** is a comma-separated alias list — the same job as Nightbot’s `-a=`. |
| `-ul=owner` / `-ul=moderator` / `-ul=twitch_vip` / `-ul=everyone` | A **Who can trigger** check between the trigger and the action, with **At least** set to broadcaster, moderator, VIP or everyone | That is Bloopbot’s full ladder for this check — broadcaster, moderator, VIP, subscriber, everyone. There is no separate follower level. |
| `-ul=regular` (Nightbot’s Regulars list) | 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. The **Regulars-only command** template wires this up for you — see [recognise regular viewers](https://bloopbot.com/docs/loyalty-and-regulars). |
| `-cd=<seconds>` | A **Cooldown** check, with a duration set on **Whole channel**, **Per viewer**, or both | Nightbot’s one number is closest to a channel-wide cooldown. A per-viewer cooldown, and letting moderators or yourself skip it, are Bloopbot additions — see [add permissions and cooldowns](https://bloopbot.com/docs/permissions-and-cooldowns). |
| Spam filters (links, caps, symbols, blacklist) | The channel-wide filters on **Moderation**, each with its own thresholds, exemptions and response | These are settings that apply to every message, not something you draw — see [set up moderation helpers](https://bloopbot.com/docs/moderation). |
| Timers (`!commands` posted on an interval, with an interval and a chat-lines setting) | A flow with an **On a timer** trigger | Set the interval in minutes, or specific days and a time of day, and optionally require that chat has moved since the last fire — see [post a recurring chat message](https://bloopbot.com/docs/timers). |
| Song requests (`!songrequest`, `!sr`, played from Nightbot’s own YouTube/SoundCloud dashboard player) | The **Song requests** flow pack, playing through your own linked Spotify account | Different service and a different source library: Nightbot plays YouTube and SoundCloud links from its dashboard player; Bloopbot plays Spotify tracks through your own Spotify Premium account — see [let chat request songs](https://bloopbot.com/docs/song-requests). Song requests may not be available on your channel yet — check [what your plan includes](https://bloopbot.com/docs/what-your-plan-includes). |

## Variables

Nightbot’s `$(…)` tokens and Bloopbot’s `$(…)` tokens look alike on purpose, but they don’t all come from the same place — Bloopbot’s come from the specific step that hands them on, mostly the trigger:

| Nightbot | Bloopbot | Notes |
| --- | --- | --- |
| `$(user)` | `$(user)` — a **Chat command** trigger’s “Who typed it” | Same syntax, same meaning: whoever ran the command. |
| `$(touser)` | `$(touser)` — “First word, or the viewer” | Also literally named `touser` in Bloopbot. Falls back to the person who typed the command when there is no first word. |
| `$(query)` | `$(query)` — “Everything after the command” | Same job: the whole rest of the message after the command word. |
| `$(1)` … `$(9)` (positional arguments) | `$(1)` … `$(9)` work the same way in any flow text field | All nine work, the same as Nightbot — the Starter pack’s own `!deaths +5` counter reads the amount as `$(3)`. Only `$(1)` (“First word after the command”) and `$(2)` (“Second word”) appear in the trigger’s own tray and **Insert…** menu; `$(3)` onward you type by hand. |
| `$(count)` (auto-incrementing per-command counter) | A declared **variable** plus a **Set a variable** action, read back as `$(var.name)` | Not automatic: you 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). |
| `$(urlfetch url)` | A **Web request** action, whose answer becomes a value later steps can use | Not an inline token — it’s a step on the canvas, and the channel has to switch **Web requests** on before it can run. Web requests may not be available on your channel yet — check [what your plan includes](https://bloopbot.com/docs/what-your-plan-includes). |
| `$(time timezone "format")` | No direct equivalent | Bloopbot has no live clock or timezone-formatting token. An **On a timer** trigger firing at a set time of day covers most of what a scheduled `$(time)` announcement was doing. |
| `$(twitch $(channel) "{{uptimeLength}}")` / `"{{game}}"` | Partial for uptime; no live token for the game | 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)`) for when the stream went live — it keeps counting after the stream ends, so pair it with a **Stream status** check if you only want it while live. For the category, the **Stream info changes** trigger hands on **Category** and **Title** at the moment you change them, but there is no token that reads the current category on demand. |

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

## Import your commands

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

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 Nightbot commands](https://bloopbot.com/admin/import/nightbot) straight from here.
2. Choose **Nightbot**. Bloopbot lists every command Nightbot has for the Twitch account you signed in with.
3. Read each row. It shows the command, who could use it, its cooldown, 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 Nightbot)` 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: !deaths carries its count over, and !time can’t be turned on until you’ve fixed its time token._

What each command becomes:

- The user level becomes a **Who can trigger** check, or a **Has a role** check for regulars. The cooldown becomes a **Cooldown** check on **Whole channel**.
- `$(user)`, `$(touser)`, `$(query)` and `$(1)` to `$(9)` stay as they are. `$(count)` becomes a counter variable named after the command. It starts at Nightbot’s current count, so a death counter at 37 carries on from 37.
- A Nightbot alias, such as `!dc` running `!discord`, becomes an extra word on `!discord`’s **Also responds to** instead of a flow of its own.

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 `$(urlfetch)`, `$(time)` or `$(channel)` (see [Variables](https://bloopbot.com/docs/coming-from-nightbot#variables-map) for what to use instead);
- a command Nightbot answered with no prefix, which in Bloopbot answers to `!` plus the word;
- a reply that starts with a chat command such as `/announce`.

The importer doesn’t bring over timers, spam filters, your Regulars list or song requests. Rebuild those as below. A regulars-only 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 Nightbot. 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. It brings ready-made command and event flows you can review, rename or leave paused — nothing goes live until you turn it on. Its own counter (`!deaths`, with mods adding to it via `!deaths +`) is a working example of a Nightbot-style tally, built from a declared variable and a **Set a variable** action.
2. For a command 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 was moderator-only, regulars-only or rate-limited in Nightbot.

![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, the way many channels run it in Nightbot:

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 Nightbot 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. Nightbot’s timers fire on an interval, optionally gated by a minimum number of chat lines since the last fire — Bloopbot’s closest match is **Only if chat has moved**, a simpler yes/no version of the same idea, not a lines-per-interval count. See [post a recurring chat message](https://bloopbot.com/docs/timers).

For Nightbot’s spam filters, open **Moderation** and configure the equivalent filter directly — links, caps, symbols, emotes and the blacklist are channel-wide settings in Bloopbot too, not something you build as a flow. Give each one the thresholds and exemptions you had in Nightbot, save, and watch chat before turning on several at once. See [set up moderation helpers](https://bloopbot.com/docs/moderation).

## Turn off the old bot

Once a Bloopbot flow or filter is live and doing the same job, turn off the matching Nightbot command, timer or filter — in the Nightbot dashboard, not here. Two bots answering the same command, posting the same timer, or filtering the same message both duplicate the reply and can make moderation logs confusing about which bot acted.

When you’re ready to retire Nightbot entirely, use its dashboard’s **Part Channel** button (or the `!part`/`!leave` chat command) to remove it from your Twitch chat, and consider `/unmod`-ing its account in Twitch chat once it has left. If Nightbot ever posted an overlay-style alert (song request now-playing, follow shout-outs) through a browser source in OBS, also remove that source once Bloopbot’s [own overlay](https://bloopbot.com/docs/widgets-in-obs) is doing the job, so the two don’t draw over each other.

## Check it before you rely on it

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

- **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.
- A real check means typing the command in your own Twitch chat (or triggering the real event) and watching for the actual reply, exactly once.

Do both: Test fire to check the wiring, then one real message in chat to confirm nothing else is still answering the same command.

## Troubleshooting

- **The importer says Nightbot has no channel for you.** Bloopbot looks for the Nightbot channel of the Twitch account you signed in with. If you used Nightbot on a different Twitch account, its commands can’t be imported here, so rebuild them as above.
- **The importer says the Nightbot channel belongs to a different Twitch account.** A channel with your name on Nightbot is linked to another Twitch account, so Bloopbot won’t read it.
- **An imported command shows `$(time …)` or another token in chat.** It was one of the rows with a warning. Open its flow and replace the token, using [Variables](https://bloopbot.com/docs/coming-from-nightbot#variables-map).
- **You get two replies.** Nightbot and Bloopbot are both still answering the same command or timer. Turn off the one you’re retiring — see “Turn off the old bot” 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)` left over from Nightbot — 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.
- **A moderator-only or regulars-only command answers for everyone, or nobody.** Confirm the **Who can trigger** or **Has a role** check sits on the wired path between the trigger and the action, and that its passing output — not its failing one — leads to your reply.
