Add cooldown on custom commands
Learn how to add cooldowns to your custom commands and control how often they can be used.
Md Shahriyar Alam
2 years ago
One member discovers your fun command and runs it forty times in a row. Your channel is ruined.
Cooldowns fix that. They control how often a command can be used — per member, per channel, or across the whole server — and in Custom Commands Bot adding one takes a single line.
Quick Answer: How Do You Add a Cooldown?
Put this in your command's Pre hook:
cooldown("1 minutes", user.id)That's it. After someone runs the command, they can't run it again for a minute. If they try, they get a message telling them how long is left, and your command never executes.
How It Works
The cooldown function takes a duration and a key:
cooldown("1 minutes", user.id)
# ^duration ^keyDuration is plain English — no seconds-since-epoch maths:
"30 seconds""1 minutes""2 hours""1 days"
Key decides who the cooldown applies to. This is the part that matters most.
Per-User vs Server-Wide Cooldowns
Per user (the usual choice)
cooldown("1 minutes", user.id)Everyone gets their own timer. One member being rate-limited doesn't affect anybody else. This is what you want for most commands.
Server-wide (global)
cooldown("1 minutes", server.id)Now there's one shared timer for the entire server. If any member runs the command, it's unavailable to everyone for the next minute.
Use this for commands that are genuinely expensive or noisy — a big announcement, a heavy API call, something that posts to a public channel. Use it deliberately, though: one impatient member can lock the command for the whole server.
Per channel
cooldown("30 seconds", channel_id)One timer per channel. Members can use the command freely in other channels, but a single channel can't be flooded.
Combined keys
Pass a list and the values are combined into one key:
cooldown("1 minutes", [user.id, channel_id])That's "this member, in this channel" — they can use the command in a different channel immediately, but not twice in the same one.
Cooldowns never leak between commands. The key is scoped to the command internally, so using
user.idin ten different commands gives you ten independent cooldowns, not one shared timer.
Where to Put It
Always in the Pre hook, and as close to the top as possible.
The cooldown stops execution when it triggers — so putting it first means a rate-limited member never causes a database lookup, an API call, or a message post:
cooldown("1 minutes", user.id)
# ...the rest of your commandCustomising the Message
By default a blocked member sees:
This command is on a cooldown, Please try again after a minute
Override it with error_message:
cooldown("1 minutes", user.id, error_message="Slow down! Try again soon.")Show the remaining time
Two placeholders get substituted for you:
| Placeholder | Becomes |
|---|---|
%time% | Human-readable remaining time, e.g. "a minute" |
%timestamp% | A Unix timestamp of when the cooldown ends |
cooldown("1 minutes", user.id, error_message="Slow down — try again in %time%.")%timestamp% is the more interesting one, because Discord renders timestamps as live countdowns:
cooldown("1 hours", user.id, error_message="On cooldown. Available <t:%timestamp%:R>")Discord displays that as "in 59 minutes" and updates it by itself as time passes. No refresh, no stale numbers.
Allowing a Few Uses First
Sometimes a hard block is too strict. count sets how many uses are allowed inside the window:
cooldown("1 minutes", user.id, count=3)Three runs per minute, then blocked until the window resets. This is a rate limit rather than a strict cooldown, and it's usually friendlier for commands members legitimately use in bursts.
Choosing a Duration
| Command type | Suggested |
|---|---|
| Fun / meme commands | "30 seconds" per user |
| Commands that post publicly | "1 minutes" per channel |
| Database or API-heavy commands | "5 minutes" per user |
| Announcements, mass DMs | "1 hours" server-wide |
| Moderation commands | Usually none — or a short one |
Start stricter than feels necessary. Loosening a cooldown never upsets anyone; tightening one after members got used to spamming does.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Everyone shares one timer | Key is server.id or a fixed value | Use user.id for per-member cooldowns |
| Cooldown does nothing | Called after the command's work | Move cooldown() to the top of Pre |
| Blocked members still trigger side effects | Same as above | Cooldown must run before anything else |
| Cooldown seems shared across commands | It isn't — keys are scoped per command | Check you're not keying on something identical by accident |
| Duration ignored | Malformed duration string | Use the "1 minutes" / "30 seconds" form |
Frequently Asked Questions
How do I add a cooldown to a Discord slash command?
Add cooldown("1 minutes", user.id) to the command's Pre hook. The duration and the key are yours to choose — the key decides whether it's per user, per channel, or server-wide.
What's the difference between a per-user and a global cooldown?
Keying on user.id gives every member their own timer. Keying on server.id creates one shared timer, so any member's use blocks everyone until it expires.
Can I show members how long is left on their cooldown?
Yes. Use %time% for readable text, or %timestamp% inside a Discord timestamp tag (<t:%timestamp%:R>) for a countdown that updates live.
Can I allow a few uses before the cooldown kicks in?
Yes — cooldown("1 minutes", user.id, count=3) permits three uses per minute before blocking.
Do cooldowns survive a bot restart?
Yes. Cooldowns are stored in the database, so nobody bypasses one by waiting for a restart.
Can different roles have different cooldowns?
Yes — that's conditional cooldowns: wrap the
cooldown() call in a permission check so admins get a shorter limit, or none at all.
Next Step
A flat cooldown treats everyone identically, which usually isn't what a server wants. Once this is working, the natural upgrade is conditional cooldowns — a short limit for staff, a longer one for everyone else, decided at runtime.
One line to start. Add it to your noisiest command right now.
Loading comments…
Need help?
Have a question, a suggestion, or stuck on something? Reach out — we're happy to help.