Lets make a strike command using custom commands bot
We are going to make a command which gives a user strike and 3 strike = kick/ban
Md Shahriyar Alam
2 years ago
Most moderation bots give you a warning system you can't change. Three strikes, or five, or whatever the developer picked — and if you want something different, you wait for a feature request.
This guide builds a /strike command that does exactly what you decide: it tracks strikes per member, tells them how many they have left, and kicks them automatically when they hit the limit. About ten lines of code, and every number in it is yours to change.
What you'll build:
/strike @Shahriyar
→ @Shahriyar has been striked. Total strikes 1
If you get 2 more strikes you will get kicked from this server.
And on the third strike, the bot kicks them.
Quick Answer: How Do Strike Commands Work?
A strike command needs three things a normal command doesn't:
- Memory — strikes must persist between runs, per member. Handled by member variables.
- A permission gate — only staff should be able to strike people.
- A threshold action — do something once the count crosses a line.
Custom Commands Bot gives you all three as one-line helpers, so the whole system fits in a single pre-code hook.
Step 1: Create the Command
In the dashboard, go to Create → Slash Command:
| Field | Value |
|---|---|
| Name | strike |
| Description | Give strike to a member |
Step 2: Add the Target Argument
Add one argument so moderators can pick who gets struck:
| Field | Value |
|---|---|
| Name | target |
| Description | The target member to strike |
| Type | MEMBER |
| Required | ✅ |
Using the MEMBER type matters. Discord shows a member picker and guarantees the value is a real member of your server — so you never have to validate it yourself, and typos become impossible.
Step 3: Write the Logic (Pre Hook)
Paste this into the Pre code box:
require_permission("administrator") # or use allowed_roles("Moderator")
current_strikes = member_var("strikes", member=target.id, default=0)
new_strikes = number(current_strikes) + 1
remaining_strikes = 3 - new_strikes
update_member_var("strikes", new_strikes, member=target.id)
response = (
f"{target.mention} has been striked. Total strikes **{new_strikes}**\n"
f"If you get **{remaining_strikes}** more strikes you will get kicked from this server."
)
if new_strikes >= 3:
kick_member(target, reason=f"Reached {new_strikes} strikes in {server.name}")
response = f"{target} has been kicked from the server for getting 3 strikes"Then set the command's Response → Content to:
{response}
Save. That's the whole feature.
What Each Line Actually Does
The permission gate
require_permission("administrator")Stops the command dead if the person running it isn't an admin — they get a clear error instead of the command working. Prefer role-based access? Swap it:
allowed_roles("Moderator", "Admin")Reading the current count
current_strikes = member_var("strikes", member=target.id, default=0)
new_strikes = number(current_strikes) + 1member_var reads a value stored against that specific member. default=0 covers a first offence, where nothing is stored yet.
number() matters more than it looks. Variables are stored as text, so current_strikes comes back as "2", not 2. Without number(), + 1 would produce "21" instead of 3. Any time you do maths on a stored variable, wrap it in number() first.
Saving the new count
update_member_var("strikes", new_strikes, member=target.id)Persisted immediately, scoped to that member in that server. Strikes survive restarts and don't leak between servers.
The threshold
if new_strikes >= 3:
kick_member(target, reason=f"Reached {new_strikes} strikes in {server.name}")reason is written to Discord's audit log, so other staff can see why the kick happened. Note it is not shown to the kicked member — see below if you want them told.
Telling the Member Before They're Kicked
The reason argument only reaches your audit log. To make sure the member knows what happened, DM them before the kick — once they're removed, you may not be able to reach them:
if new_strikes >= 3:
send_dm(target, f"You reached {new_strikes} strikes and were kicked from {server.name}")
kick_member(target, reason=f"Reached {new_strikes} strikes")
response = f"{target} has been kicked from the server for getting 3 strikes"Variations Worth Making
Ban instead of kick — a kicked member can rejoin with a fresh invite:
ban_member(target, reason="Reached 3 strikes")Escalate instead of jumping straight to a kick:
if new_strikes == 2:
send_dm(target, "Final warning — one more strike and you're out.")
elif new_strikes >= 3:
kick_member(target, reason="Reached 3 strikes")Change the threshold — every 3 in the code is just a number. Want five strikes? Change 3 to 5 in both places (remaining_strikes and the if). Nothing else moves.
A /strikes lookup command so staff can check someone without punishing them:
count = member_var("strikes", member=target.id, default=0)
response = f"{target.mention} has **{count}** strikes."A /clearstrikes command for appeals or a seasonal reset:
require_permission("administrator")
update_member_var("strikes", 0, member=target.id)
response = f"Cleared all strikes for {target.mention}."Together those three commands are a complete moderation system that no fixed-feature bot will match — because you decided the rules.
Making It Production-Ready
Three settings worth turning on for a moderation command:
Default permissions — set the command to require Kick Members or Manage Server. Discord then hides it from regular members entirely, rather than letting them run it and get an error.
Ephemeral — if you'd rather strikes weren't announced publicly, mark the response ephemeral so only the moderator sees it.
Don't let staff strike each other — a quick guard:
if has_permission(target, "administrator"):
response = "You can't strike an administrator."
else:
# ...strike logic hereTroubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| "Missing permission to kick member" | Bot's role is below the target's | Move the bot's role above the members it must moderate |
| Strikes reset every time | Reading without member= | Always pass member=target.id, or you're reading a server-wide variable |
Count jumps 1 → 11 → 111 | Missing number() | Wrap stored variables in number() before doing maths |
| Regular members can run it | No permission gate | Add require_permission(...) and set default permissions |
| Nothing appears in the reply | Response content not set | Set Response → Content to {response} |
That second row is the classic. member_var("strikes") without member= reads a server variable, so every member shares one counter — everyone sits at whatever the last person's total was.
Frequently Asked Questions
How do I make a warning system for Discord?
Store a count per member with update_member_var, read it back with member_var, and act when it crosses your threshold. The whole system is one pre-code hook on a slash command — no database setup required.
Can I change the number of strikes before a kick?
Yes. The threshold is a plain number in your code. Change 3 to whatever you want in the remaining_strikes line and the if — that's the only edit needed.
Do strikes persist if the bot restarts?
Yes. Member variables are stored in the database, not in memory. Strikes survive restarts, deploys, and outages.
Are strikes shared between servers?
No. Variables are scoped per server, so a member's strikes in one server have no effect anywhere else.
Can I see how many strikes someone has without striking them?
Build a second /strikes command that reads member_var without updating it — the lookup version shown above.
Why does my strike count concatenate instead of adding?
Stored variables come back as text, so "2" + 1 behaves like string joining. Wrap the value in number() before doing arithmetic.
Why Build It Yourself
A dedicated moderation bot gives you a strike system. This gives you your strike system — different thresholds per role, DMs worded your way, escalating punishments, a /clearstrikes for appeals, strikes that decay after a month.
Every one of those is a few lines in the same hook, not a feature request you wait on.
Now go run it:
/strike @Shahriyar
Loading comments…
Need help?
Have a question, a suggestion, or stuck on something? Reach out — we're happy to help.