Docs
Developer Documentation

Leaderboard Providers

Register custom leaderboards, ranking algorithms, and unit formatters.

Modules can declare custom leaderboard providers that automatically integrate with Discord's /leaderboard slash command and the web dashboard's Leaderboards view.

Leaderboard providers reside in resources/leaderboards/ and load from every *.js file located directly in that directory.

Base Class Definition

modules/example/resources/leaderboards/activity.js
import { Leaderboards } from "#medusa/modules";

export class ActivityLeaderboard extends Leaderboards {
    constructor(medusa) {
        super(medusa, {
            name: "activity_score",
            label: "Activity Score",
            group: "Community",
            format: "number",
            emoji: "⭐",
            unit: "Points",
            singular: "Point",
            order: 1
        });
    }

    async list(guild) {
        const model = this.medusa.modules.models.get(this.module, "user_scores");
        if (!model) return [];

        const records = await model.list({ guildId: guild.id });
        return records
            .sort((a, b) => b.score - a.score)
            .slice(0, 100)
            .map(record => ({
                userId: String(record.userId),
                value: record.score,
                sub: `Level ${record.level} • Streak: ${record.streak} days`,
                stats: [
                    { label: "Level", value: record.level },
                    { label: "Streak", value: `${record.streak}d` }
                ]
            }));
    }
}

Constructor Options

The configuration object passed to super(medusa, meta) accepts the following properties:

PropertyTypeDefaultDescription
namestringRequiredUnique leaderboard identifier.
labelstringnameDisplay title shown in menus, embeds, and dashboard tables.
groupstring"General"Categorization group used to organize multiple leaderboards.
formatstring"number"Value formatting style: "number", "currency", or "duration".
emojistring""Emoji prefix displayed next to values.
unitstring""Plural unit name appended to values (e.g. "Credits", "Messages").
singularstringunitSingular unit name used when value is 1 (e.g. "Credit", "Message").
ordernumber0Sort priority among leaderboards within the same group.

Supported Formatting Modes

The format property determines how Medusa renders values in Discord embeds and dashboard widgets:

Format ModeSample OutputFormatting Rules
"number"1,250 PointsLocalized integer formatting with unit suffix.
"currency"$ 5,000 CoinsPrepends emoji or currency symbol and appends unit label.
"duration"4h 12mConverts numeric seconds into human-readable hours and minutes.

The list(guild) Method

Every provider must implement async list(guild) which receives the active Discord.js Guild instance and returns an array of ranked participant objects.

Return Item Schema

PropertyTypeRequiredDescription
userIdstringYesDiscord snowflake ID of the member. Used to resolve usernames and avatars.
valuenumberYesRaw numeric value used for ranking calculations and sorting.
displaystringNoOptional pre-formatted text override replacing automatic numeric formatting.
substringNoSubtitle text displayed below the user's name in list items.
statsArray<object>NoArray of supplementary metric objects containing label and value (string or number) rendered as badges.

Leaderboard Manager Methods

The root this.medusa.leaderboards service provides methods used across Discord commands and web views:

const allTypes = this.medusa.leaderboards.types();

const rows = await this.medusa.leaderboards.list("activity_score", guild);

const page = this.medusa.leaderboards.paginate(rows, 0, 10);

const position = this.medusa.leaderboards.position(rows, interaction.user.id);

On this page