Custom Commands
Build your own commands without writing code. Choose between simple text responses with dynamic variables, or the visual Block Editor, a visual scripting system with conditions, loops, math, persistent storage, and embeds.
Overview
Custom commands are created and managed entirely from the dashboard: open your server, then Custom Commands in the sidebar. Every command has a trigger (what activates it) and a response. There are two response modes:
Text Response
A single message sent back when the command triggers. Supports all template variables. Perfect for FAQs, links, and quick info commands.
Visual Blocks
A sequence of blocks executed top to bottom: send messages, add roles, check conditions, roll dice, store data, and more. No code required.
- Four trigger types: command, exact match, contains, and regex
- 31 building blocks across 7 categories
- Per-server persistent database for counters, scores, and state
- Cooldowns scoped per user, channel, or server
- Enable / disable commands without deleting them
Creating a Command
- Open the Custom Commands page In your server dashboard, click Custom Commands, then Create Command.
- Set the trigger Give the command a name/trigger and pick a trigger type. Optionally make it case-sensitive.
- Choose a response mode Pick Text for a simple reply, or Visual Blocks to open the block editor and build logic.
- Save and test Save the command and trigger it in your server. Changes apply instantly, no restart needed.
Trigger Types
| Type | Fires When |
|---|---|
Command | The message starts with the bot prefix + trigger (e.g. !hello) |
Exact Match | The whole message equals the trigger text exactly |
Contains | The trigger text appears anywhere in the message |
Regex | The message matches your regular expression pattern |
Member Joins | Someone joins the server. There is no trigger text: you pick the channel its messages go to instead |
Member Leaves | Someone leaves the server, same as above |
Join and leave commands have no triggering message
Add Reaction and Delete Trigger therefore do nothing in them, and Reply to User posts in the channel you picked. Everything else works normally, and {{user}} is the member who joined or left.
Careful with "Contains" and "Regex"
These can fire on normal conversation. Combine them with a cooldown, or use conditions inside the block editor to limit where they respond.
Template Variables
Variables use double curly braces and are replaced when the command runs. They work in text responses and in any text field inside blocks (messages, embed fields, database keys…).
User
| Variable | Output |
|---|---|
{{user}} | Mentions the user (@Username) |
{{user.id}} | The user's Discord ID |
{{user.username}} | Username as plain text |
{{user.displayname}} | Server display name (nickname if set) |
{{user.avatar}} | URL of the user's avatar image |
Server
| Variable | Output |
|---|---|
{{server}} | Server name |
{{server.id}} | Server ID |
{{server.membercount}} | Current member count |
{{server.icon}} | URL of the server icon |
Channel
| Variable | Output |
|---|---|
{{channel}} | Mentions the channel (#channel) |
{{channel.id}} | Channel ID |
{{channel.name}} | Channel name as plain text |
Arguments
Arguments are the words a user types after the trigger. For example, in !say hello world, the arguments are "hello world".
| Variable | Output |
|---|---|
{{args}} | Everything after the trigger |
{{args.0}} | The first argument (then {{args.1}}, {{args.2}}…) |
Custom Variables
Any variable you create with the Set Variable, Random Number, math, or database Get Value blocks becomes available as {{yourVariableName}} in all later blocks, and can be branched on with If Variable. Blocks that do not ask for a name write a fixed one: randomNum, result for the math blocks, and loopIndex inside a Repeat.
Text Response Example
<code v-pre>Hey {{user}}, welcome to {{server}}! We're now {{server.membercount}} members strong.</code>The Block Editor
Blocks run from top to bottom. Click the + on any gap in the flow to search the block list and place one exactly there, fill in its settings, and drag a block by its handle to reorder it. Condition and loop blocks hold nested blocks that only run when the condition passes, so drop blocks straight into their body.
Actions
| Block | What It Does |
|---|---|
Send Message | Sends a message to the channel |
Reply to User | Replies directly to the triggering message |
Send DM | Sends a private message to the user (silently skipped if their DMs are closed) |
Add Reaction | Reacts to the triggering message with an emoji |
Delete Trigger | Deletes the message that triggered the command |
Add Role | Gives the user a role |
Remove Role | Removes a role from the user |
Wait | Pauses execution for 1-60 seconds |
Conditions
Each condition holds nested blocks that only run when it passes. Most carry a NOT switch to invert them; If Variable instead offers the inverted comparisons directly.
| Block | Passes When |
|---|---|
If Has Role | The user has the selected role |
If In Channel | The command ran in the selected channel |
If Is Admin | The user has the Administrator permission |
If Message Contains | The trigger message contains specific text |
If Variable | A stored variable is equal to, not equal to, contains or does not contain a value; is greater than, greater than or equal to, less than, or less than or equal to it; or is set or empty. Text compares ignore case, the four size compares treat both sides as numbers |
Random Chance | A configurable percentage roll succeeds (e.g. 25%) |
Variables
| Block | What It Does |
|---|---|
Set Variable | Stores a value under a name for use as {{name}} later |
User / Server / Channel / Arguments | Reference cards listing the built-in variables; they don't execute anything |
Control Flow
| Block | What It Does |
|---|---|
Repeat | Runs its nested blocks 1-10 times |
Stop | Immediately ends command execution |
Math
| Block | What It Does |
|---|---|
Random Number | Stores a random integer between min and max in a variable |
Add / Subtract / Multiply | Computes a result from two values and stores it in a variable |
Embeds
| Block | What It Does |
|---|---|
Send Embed | Sends a rich embed to the channel |
Reply with Embed | Replies to the user with a rich embed |
Database blocks get their own section below.
Command Database
The database blocks give your commands memory. Each server gets its own key-value store that persists between command runs, ideal for counters, scores, opt-in lists, and daily streaks.
| Block | What It Does |
|---|---|
Get Value | Reads a key into a variable (with a default if missing) |
Set Value | Writes a value to a key |
Add to Number | Increments a numeric key and stores the new total in a variable |
Check Exists | Stores whether a key exists (true/false) in a variable |
Delete Value | Removes a key entirely |
User-Scoped Keys
Every database block has a user-scoped toggle. When enabled, the key is stored separately per user, so points with user-scope on gives every member their own counter, while the same key without user-scope is shared by the whole server.
Keys support variables too: a key like warnings-{{user.id}} achieves manual per-user storage if you need to mix scopes.
You can inspect and manage all stored values on the dashboard's Custom Commands > Database page.
Embeds
The embed blocks open a mini embed builder. Every field accepts template variables.
| Field | Description |
|---|---|
Title | Bold heading at the top of the embed |
Description | Main body text (supports Discord markdown) |
Color | Hex color of the embed's side bar (defaults to teal) |
Author | Small header line with optional icon URL |
Thumbnail | Small image in the top-right corner |
Image | Large image below the description |
Fields | Name/value pairs, optionally displayed inline side by side |
Footer | Small text at the bottom |
Cooldowns
Prevent spam by setting a cooldown in seconds (0 = none). The scope decides who shares the timer:
| Scope | Behavior |
|---|---|
Per User | Each member has their own cooldown |
Per Channel | One timer per channel, shared by everyone in it |
Per Server | One global timer for the whole server |
Examples
1. Simple FAQ (Text Response)
Trigger type Command, trigger ip:
Text Response
<code v-pre>Our Minecraft server IP is **play.example.com**. See you there, {{user.displayname}}!</code>2. 8-Ball (Blocks)
- Random Number min 1, max 4 > variable
roll - If Message Contains "?", nested:
The magic 8-ball says: answer #{{roll}}…Reply to User- If Message Contains "?" (negated), nested:
- Reply to User "That doesn't look like a question!"
3. Per-User Daily Counter (Blocks + Database)
- Add to Number key
daily-claims, user-scoped, +1 > variabletotal - Reply with Embed title
Daily Reward, description{{user}} you've claimed {{total}} rewards so far!
4. Role-Gated Response (Blocks)
- If Has Role @VIP, nested:
- Reply to User "Welcome to the VIP lounge!"
- Stop
- Reply to User "You need the VIP role for this command."
5. Server Stats (Blocks + Embed)
- Send Embed title
{{server}} Stats, thumbnail{{server.icon}}, fieldMembers={{server.membercount}}
Limits & Tips
| Limit | Value |
|---|---|
Wait block | 1-60 seconds per block |
Repeat block | 1-10 iterations |
Triggers | Commands only fire for humans; bot messages are ignored |
Role hierarchy
Add Role / Remove Role blocks only work if Natsumi's bot role is above the target role in the server's role list.
Build incrementally
Start with a Reply block to confirm the trigger works, then add conditions and storage one block at a time. Disabled commands keep their blocks, so you can pause a command while reworking it.
