What a Discord bot license system does
A Discord bot license system is code that checks whether a bot user has paid for or been granted permission to use your bot. When someone runs a command, the bot looks up their user ID in a database and decides whether to let the command work or block it. This is how bot creators control who can use premium features, limit free-tier access, or prevent unauthorized copies of their bot from running.
The system sits between the user's command and the bot's response. If the license check passes, the command executes normally. If it fails, the bot sends a message like "You don't have a license for this feature" and stops. You control what counts as valid — a paid subscription, a one-time purchase, a whitelist of trusted servers, or anything else you define.
Key Takeaways
- A license system requires three parts: a database to store user IDs and their license status, code in your bot that checks that database before running commands, and a way to issue or revoke licenses when users pay or lose access.
- The simplest approach uses a JSON file or free database like Firebase or MongoDB to track which user IDs are licensed, and a middleware function that runs before every command.
- You must decide whether to check licenses per-user, per-server, or per-command, because each approach requires different database structure and different code logic.
- License keys are optional — you can issue them to users, or you can straightforward mark their Discord user ID as licensed in your database without giving them a visible key to enter.
- Testing your license system before release means creating test accounts, marking some as licensed and others as not, and confirming the bot behaves correctly for each group.
Choosing where to store license data
Your license system needs somewhere to store which users or servers are licensed. The three most common choices are a JSON file, a cloud database, or a spreadsheet.
JSON files work for small bots with fewer than a few hundred licensed users. You create a file called `licenses.json` that holds an array or object of user IDs marked as licensed. Your bot reads this file every time someone runs a command. The downside is that the file lives on your computer or server, and if your bot crashes or restarts, it has to reload the file from disk — this is slow for large lists. Updating the file means stopping the bot, editing it, and restarting.
Cloud databases like Firebase (free tier available), MongoDB, or Supabase are faster and let you update licenses without restarting your bot. Your bot connects to the database over the internet and checks a user's license status in milliseconds. These services have free tiers that work for testing and small deployments. The trade-off is that you need to learn how to connect to the database and write queries — the code is more complex than reading a JSON file.
Spreadsheets like Google Sheets can work if you use a library to read them, but they are slower than databases and not designed for this use. They are useful only if you want a human-readable way to manage licenses manually, and you do not mind the bot taking a second or two to check each command.
Building the license check into your bot code
Once you have chosen where to store licenses, you need to add code that checks the database before running commands. The exact code depends on which Discord bot library you use — discord.py, discord.js, or another — but the logic is the same.
In discord.py, you write a function called a "check" that runs before a command. This function takes the user ID from the message, looks it up in your database, and returns True if they are licensed or False if they are not. If it returns False, the bot sends an error message instead of running the command. Here is the shape of it:
def is_licensed(ctx): user_id = ctx.author.id if user_id in licensed_users: return True else: return False @bot.command() @commands.check(is_licensed) async def premium_command(ctx): await ctx.send("This is a premium feature")
In discord.js, you add a check inside each command that reads the user ID and queries your database. The pattern is similar — get the user ID, check the database, and either run the command or send an error.
The key decision is where to put the check. You can add it to every single command (tedious and error-prone), or you can create a middleware function that runs before all commands and blocks unlicensed users before they reach the command code. Middleware is cleaner because you write the check once and it applies everywhere.
Deciding what to license — user, server, or command
Before you write code, decide what unit you are licensing. Are you licensing individual users, entire Discord servers, or specific commands?
Per-user licensing means a single Discord user can run premium commands anywhere — in any server, any time. Your database stores user IDs. This works well if your bot is a personal tool or a utility that users bring into their own servers. The downside is that one person can share their license with friends by inviting them to the same server.
Per-server licensing means a server owner pays once and everyone in that server can use premium features. Your database stores server IDs instead of user IDs. This works well for moderation bots, music bots, or tools that serve entire communities. The downside is that you have to track which user is the server owner or has permission to manage the bot, so you do not license the wrong person.
Per-command licensing means different commands have different license requirements. Some commands are free, others require a license. Your database can store either user IDs or server IDs, but your check function has to know which command is being run and what license level it needs. This is more complex but gives you the most control — you can offer a free tier with basic commands and a paid tier with advanced ones.
Issuing and revoking licenses
You need a way to mark users or servers as licensed. The simplest method is a command that only you can run — something like `!addlicense @user` that adds their ID to the database. You run this command manually when someone pays or when you want to give someone access.
A more automated approach is to connect your bot to a payment processor like Stripe or Gumroad. When someone buys a license, the payment processor sends a webhook (an automatic message) to your bot, and your bot adds their user ID to the database without you having to do anything. This requires more setup but scales better if you have many customers.
To revoke a license, you remove the user or server ID from the database. If you are using a JSON file, you edit the file and restart the bot. If you are using a cloud database, you delete the record and the change takes effect when ready — the next time that user runs a command, the check will fail.
You should also add an expiration date to licenses. Store a timestamp in your database alongside each user ID, and check whether the current date is before or after that timestamp. When the date passes, the license expires and the user loses access until they renew.
Testing your license system before release
Before you release your bot to the public, test that the license system works correctly. Create at least two test Discord accounts — one that you mark as licensed in your database and one that you do not. Run commands with both accounts and confirm that the licensed account can use premium features while the unlicensed account gets blocked.
Test edge cases: what happens if a user ID is in the database but spelled wrong? What if the database connection fails — does the bot crash or does it deny access safely? What if a user runs a command right as their license expires — do they get blocked or do they get one more use? These scenarios matter because they affect how your users experience the bot.
Also test that your license check does not slow down the bot. If checking the database takes more than a second per command, users will notice lag. If you are using a cloud database, test from the same region where your bot runs, because network distance affects speed.
Common mistakes to avoid
Do not store license keys in your bot code or in a public GitHub repository. If someone reads your code and finds a hardcoded key, they can use it to bypass the license check. Always store keys in environment variables or a private database that your bot connects to at runtime.
Do not assume that checking a license once per session is enough. Check it every time a command runs, because a user's license might expire or be revoked between commands. The overhead is small and the security is much better.
Do not make the error message too helpful. If you tell an unlicensed user exactly how to get a license, you are also telling someone who wants to crack your system what they need to do. Keep error messages straightforward: "You do not have permission to use this command."
Do not forget to log license checks. Keep a record of who tried to use premium features and whether they succeeded. This helps you spot abuse and understand which features are popular.
Frequently Asked Questions
Can I use a license key that users enter, or do I have to check their Discord user ID?
You can do either. A license key is a string like "ABC123XYZ" that a user enters with a command, and your bot checks whether that key exists in your database. This works but is less convenient than checking the user ID automatically. User ID checking is simpler because the bot already knows who is running the command — no manual entry needed.
What if someone copies my bot code and runs their own version with no license system?
You cannot stop them technically, but you can make it harder. Keep your bot code private on GitHub (not public). If your bot connects to an API or database that you control, require authentication — only your official bot instance has the credentials. This way, even if someone copies your code, their copy will not work without your permission.
How do I handle licenses for bots that run on multiple servers?
If you are licensing per-server, check the server ID instead of the user ID. If you are licensing per-user, check the user ID and let them use the bot in any server they join. The database structure is the same — you just change what ID you look up.
Do I need a payment processor, or can I manage licenses manually?
You can manage licenses manually if you have a small number of users. Create a command that only you can run, like `!addlicense @user`, and run it when someone asks for access or pays you outside the bot. For larger scale, a payment processor like Stripe automates this and is worth the setup time.
What happens if my database goes down?
Your bot should have a fallback behavior. You can either deny all commands until the database is back (safest for paid features), or allow all commands (risky because unlicensed users get free access). The best approach is to cache the license list in your bot's memory and only check the database every few minutes, so a brief outage does not break everything.