Custom Commands docsCustom CommandsDocs

Search docs

Find a page, function or guide

HomeSupportDashboard

Getting started

  • Introduction
  • Your first command
  • How a command runs
  • Variables in replies
  • Text commands
  • Events
  • Using Slushy

Guides

  • Welcome messages
  • Role menus
  • Auto moderation
  • Social alerts
  • Moderation commands
  • Levels and XP
  • Economy and coins
  • Ticket system
  • Giveaways
  • Poll
  • Button game
  • Reminders

Concepts

  • Buttons and menus
  • Forms
  • Saving data
  • Permissions and cooldowns
  • Limits and premium
  • Common mistakes

API reference

  • Response
  • Messages
  • Embeds
  • Members and roles
  • Channels
  • Storage
  • Checks
  • Views
  • Components
  • Modals
  • Interactions
  • Paginators
  • Web and files
  • Scheduling
  • Server events and polls
  • Time
  • Waiting
  • Utilities
  • Objects
  • Event variables

Examples

  • /8ball
  • /coinflip
  • /avatar
  • /serverinfo
  • /rank
  • /remind

Guides

View .md

Levels and XP

Give members XP for chatting, announce level-ups, and add /rank and /leaderboard commands.

You will build a level system:

  • Members get 15 to 25 XP (experience points) for chatting. At most once a minute, so spam does not help.
  • The bot posts a message when someone reaches a new level.
  • /rank shows a member's level and XP.
  • /leaderboard shows the top 10.

Premium needed

XP for chatting needs a Message event. Message events run only on servers with a premium plan. /rank and /leaderboard work on every plan.

What you need#

  • A premium plan on the server.
  • About 10 minutes.

The XP is saved in a Mongo database. That is a place to keep data that lasts, with one row (called a document) per member. You do not need to set it up. It is made the first time the code saves something. Learn more in Saving data.

How levels work#

A member's level comes from their XP:

LevelXP needed
1100
2400
3900
52,500
1010,000

The rule is: level = square root of (XP ÷ 100). Each level takes a bit longer than the last.

1. Give XP for messages#

On the dashboard, open Create → Event.

FieldValue
NameXP for messages
TypeMESSAGE (Pro Only)

Paste this in Code:

python
def level_of(xp):
    return int((xp / 100) ** 0.5)

# Bots and webhooks do not earn XP.
if user and not user.is_bot:
    levels = SlashMongo("levels")
    uid = str(user.id)
    now = int(unix_timestamp)
    doc = await levels.find_one({"_id": uid}) or {"xp": 0, "last": 0}

    # One reward per minute.
    if now - doc.get("last", 0) >= 60:
        old_xp = doc.get("xp", 0)
        new_xp = old_xp + randomNumber(15, 25)
        await levels.update_one(
            {"_id": uid},
            {"$set": {"xp": new_xp, "last": now}},
            upsert=True,
        )

        if level_of(new_xp) > level_of(old_xp):
            send_message(
                channel,
                f"{user.mention} reached **level {level_of(new_xp)}**!",
            )

Press save.

What the code does:

  1. Skips bots.
  2. Loads the member's row. A new member starts at 0 XP.
  3. Stops if they got XP less than 60 seconds ago.
  4. Adds 15 to 25 XP and saves. upsert=True makes the row if it is not there yet.
  5. Posts a message when the level goes up.

Note

Database functions like find_one and update_one need await in front. Most other functions do not. See Storage.

2. Make /rank#

Open Create → Slash Command.

FieldValue
Command Namerank
DescriptionShow your level

Under Arguments, add a Member argument:

FieldValue
Namemember
DescriptionWhose rank to show
RequiredOff

Paste this in Pre-hook:

python
def level_of(xp):
    return int((xp / 100) ** 0.5)

target = member or user
doc = await SlashMongo("levels").find_one({"_id": str(target.id)})
xp = doc["xp"] if doc else 0
level = level_of(xp)
next_xp = (level + 1) ** 2 * 100

set_content(
    f"**{target.display_name}** is level **{level}**\n"
    f"XP: {intcomma(xp)} / {intcomma(next_xp)}"
)

Leave the Response box empty. set_content fills the reply.

When nobody is picked, member is empty, so member or user falls back to the person who ran the command.

3. Make /leaderboard#

Make another slash command named leaderboard. Paste this in Pre-hook:

python
def level_of(xp):
    return int((xp / 100) ** 0.5)

top = await SlashMongo("levels").find({}, sort=[("xp", -1)], limit=10)

lines = []
for place, doc in enumerate(top, start=1):
    lines.append(
        f"**{place}.** <@{doc['_id']}> — level {level_of(doc['xp'])} "
        f"({intcomma(doc['xp'])} XP)"
    )

set_embed(Message(
    title=f"Top members in {server.name}",
    description="\n".join(lines) or "Nobody has XP yet. Start chatting!",
    color="#5865F2",
))

sort=[("xp", -1)] puts the highest XP first. limit=10 keeps only 10 rows, so the command stays fast on big servers.

Mentions inside an embed do not ping anyone, so the leaderboard is quiet.

4. Test it#

  1. Send a message in your server.
  2. Run /rank. You have 15 to 25 XP.
  3. Send another message right away. Run /rank again. Nothing changed: that is the one-minute wait.
  4. Run /leaderboard.

Not working? Open Logs → Error Logs on the dashboard. Errors from your code show there.

Ideas#

  • Level roles. In the event, after the level-up message, give a role: if level_of(new_xp) == 5: add_roles(user, "Level 5").
  • No XP in some channels. Add and channel.name != "bot-spam" to the first if.
  • Image rank card. Design one in Image Templates and send it with render_template. See Web and files.
  • Reset everyone. Make a staff-only command that runs await SlashMongo("levels").delete_many({}).
PreviousModeration commandsNext Economy and coins

On this page

  • What you need
  • How levels work
  • 1. Give XP for messages
  • 2. Make /rank
  • 3. Make /leaderboard
  • 4. Test it
  • Ideas
Custom CommandsCustom Commands

The #1 Custom Commands Discord bot — build commands, events and databases with zero boilerplate.

Join the support server

Product

  • Overview
  • Why us?
  • Premium
  • Template shop

Features

  • AI Agent
  • Reaction roles
  • Welcome messages
  • Embed builder
  • Social alerts
  • Custom bot

Resources

  • Docs
  • Blog
  • Support
  • Dashboard

Company

  • Privacy
  • Terms
  • Contact
contact@ccbot.app

2 Frederick Street, London, WC1X 0ND

Payments secured by Stripe

© WEiRDSOFT LTD. All rights reserved.

Custom Commands