Get Leaderboard Metadata
Before displaying or interacting with leaderboards, you need to load their metadata. Metadata includes leaderboard IDs, names, icons, score ordering, and available collections.
Overview
The loadleaderboardmetadata method retrieves configuration information for all leaderboards in your game. This data is essential for building leaderboard UIs and understanding how each leaderboard behaves.
Leaderboard metadata is configured in your Moitribe dashboard. The SDK retrieves this configuration at runtime.
Basic Usage
JavaScript Example
MoitribeSDK('my-game-id', 'loadleaderboardmetadata', {
onlyData: true,
callback: (result) => {
if (result.success) {
console.log('Leaderboards:', result.leaderboards);
result.leaderboards.forEach((lb) => {
console.log(`ID: ${lb.leaderboardID}`);
console.log(`Name: ${lb.leaderboardName}`);
console.log(`Order: ${lb.leaderboardScoreOrder}`);
});
} else {
console.error('Failed to load leaderboards');
}
}
});
TypeScript Example
import MoitribeSDK from '@veniso/moitribe-js';
import type { LeaderboardMeta } from '@veniso/moitribe-js';
interface MetadataResult {
success: boolean;
leaderboards: LeaderboardMeta[];
msg?: string;
}
MoitribeSDK('my-game-id', 'loadleaderboardmetadata', {
onlyData: true,
callback: (result: MetadataResult) => {
if (result.success) {
result.leaderboards.forEach((lb: LeaderboardMeta) => {
console.log(`${lb.leaderboardName}:`);
console.log(` ID: ${lb.leaderboardID}`);
console.log(` Icon: ${lb.leaderboardIconURL}`);
console.log(` Score Order: ${lb.leaderboardScoreOrder === 1 ? 'Descending' : 'Ascending'}`);
});
}
}
});
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
onlyData | boolean | Yes | Set to true to get data programmatically |
callback | function | Yes | Called with the result |
Always set onlyData: true when using this method. This ensures you receive data in the callback rather than triggering UI elements.
Response Format
The callback receives a result object:
{
success: boolean;
leaderboards: LeaderboardMeta[];
msg?: string; // Error message if success is false
}
LeaderboardMeta Structure
Each leaderboard in the array has this structure:
interface LeaderboardMeta {
leaderboardID: string; // Unique identifier
leaderboardName: string; // Display name
leaderboardIconURL: string; // URL to icon image
leaderboardScoreOrder: number; // 1 = descending, -1 = ascending
leaderboardCollection: {
Social: number; // Social collection ID
All: number; // Global collection ID
};
}
Example Response
{
success: true,
leaderboards: [
{
leaderboardID: 'high-scores',
leaderboardName: 'High Scores',
leaderboardIconURL: 'https://cdn.moitribe.com/icons/trophy.png',
leaderboardScoreOrder: 1, // Higher is better
leaderboardCollection: {
Social: 12345,
All: 67890
}
},
{
leaderboardID: 'speed-run',
leaderboardName: 'Speed Run',
leaderboardIconURL: 'https://cdn.moitribe.com/icons/timer.png',
leaderboardScoreOrder: -1, // Lower is better
leaderboardCollection: {
Social: 12346,
All: 67891
}
}
]
}
Common Use Cases
Build Leaderboard Selector
Create a UI for players to choose leaderboards:
function buildLeaderboardMenu() {
MoitribeSDK('my-game-id', 'loadleaderboardmetadata', {
onlyData: true,
callback: (result) => {
if (result.success) {
const menu = document.getElementById('leaderboard-menu');
result.leaderboards.forEach((lb) => {
const button = document.createElement('button');
button.className = 'leaderboard-option';
button.innerHTML = `
<img src="${lb.leaderboardIconURL}" alt="${lb.leaderboardName}">
<span>${lb.leaderboardName}</span>
`;
button.onclick = () => openLeaderboard(lb.leaderboardID);
menu.appendChild(button);
});
}
}
});
}
function openLeaderboard(leaderboardId) {
// Load and display scores for this leaderboard
console.log('Opening leaderboard:', leaderboardId);
}
Store Metadata for Later Use
Cache leaderboard configuration:
let leaderboardCache = {};
function loadAndCacheMetadata() {
MoitribeSDK('my-game-id', 'loadleaderboardmetadata', {
onlyData: true,
callback: (result) => {
if (result.success) {
// Store in cache
result.leaderboards.forEach((lb) => {
leaderboardCache[lb.leaderboardID] = lb;
});
console.log('Leaderboards cached:', Object.keys(leaderboardCache));
}
}
});
}
function getLeaderboardInfo(leaderboardId) {
return leaderboardCache[leaderboardId] || null;
}
function getLeaderboardName(leaderboardId) {
const lb = leaderboardCache[leaderboardId];
return lb ? lb.leaderboardName : 'Unknown';
}
function isDescending(leaderboardId) {
const lb = leaderboardCache[leaderboardId];
return lb ? lb.leaderboardScoreOrder === 1 : true;
}
// Load metadata when game starts
loadAndCacheMetadata();
TypeScript Leaderboard Manager
Create a type-safe manager class:
import type { LeaderboardMeta } from '@veniso/moitribe-js';
class LeaderboardManager {
private static metadata: Map<string, LeaderboardMeta> = new Map();
private static loaded: boolean = false;
static async load(gameId: string): Promise<void> {
return new Promise((resolve, reject) => {
MoitribeSDK(gameId, 'loadleaderboardmetadata', {
onlyData: true,
callback: (result: { success: boolean; leaderboards: LeaderboardMeta[] }) => {
if (result.success) {
result.leaderboards.forEach((lb) => {
this.metadata.set(lb.leaderboardID, lb);
});
this.loaded = true;
resolve();
} else {
reject(new Error('Failed to load leaderboard metadata'));
}
}
});
});
}
static getMetadata(leaderboardId: string): LeaderboardMeta | undefined {
return this.metadata.get(leaderboardId);
}
static getName(leaderboardId: string): string {
const lb = this.metadata.get(leaderboardId);
return lb?.leaderboardName || 'Unknown Leaderboard';
}
static getIcon(leaderboardId: string): string {
const lb = this.metadata.get(leaderboardId);
return lb?.leaderboardIconURL || '';
}
static isDescending(leaderboardId: string): boolean {
const lb = this.metadata.get(leaderboardId);
return lb?.leaderboardScoreOrder === 1;
}
static getAllLeaderboards(): LeaderboardMeta[] {
return Array.from(this.metadata.values());
}
static isLoaded(): boolean {
return this.loaded;
}
}
// Usage
await LeaderboardManager.load('my-game-id');
const leaderboards = LeaderboardManager.getAllLeaderboards();
console.log('Available leaderboards:', leaderboards.length);
Display Leaderboard Cards
Create cards showing all leaderboards:
function displayLeaderboardCards() {
MoitribeSDK('my-game-id', 'loadleaderboardmetadata', {
onlyData: true,
callback: (result) => {
if (result.success) {
const container = document.getElementById('leaderboards-container');
container.innerHTML = '';
result.leaderboards.forEach((lb) => {
const card = createLeaderboardCard(lb);
container.appendChild(card);
});
}
}
});
}
function createLeaderboardCard(leaderboard) {
const card = document.createElement('div');
card.className = 'leaderboard-card';
const orderText = leaderboard.leaderboardScoreOrder === 1
? 'Higher is better'
: 'Lower is better';
card.innerHTML = `
<div class="card-header">
<img src="${leaderboard.leaderboardIconURL}" alt="Icon">
<h3>${leaderboard.leaderboardName}</h3>
</div>
<div class="card-body">
<p class="score-order">${orderText}</p>
<button onclick="viewLeaderboard('${leaderboard.leaderboardID}')">
View Rankings
</button>
</div>
`;
return card;
}
function viewLeaderboard(leaderboardId) {
// Navigate to leaderboard view
window.location.href = `#/leaderboard/${leaderboardId}`;
}
Filter Leaderboards by Type
Separate leaderboards by score order:
function categorizeLeaderboards() {
MoitribeSDK('my-game-id', 'loadleaderboardmetadata', {
onlyData: true,
callback: (result) => {
if (result.success) {
const ascending = [];
const descending = [];
result.leaderboards.forEach((lb) => {
if (lb.leaderboardScoreOrder === 1) {
descending.push(lb);
} else {
ascending.push(lb);
}
});
console.log('High Score Leaderboards:', descending.length);
console.log('Low Score Leaderboards:', ascending.length);
displayCategorizedLeaderboards(descending, ascending);
}
}
});
}
function displayCategorizedLeaderboards(descending, ascending) {
// Display high score leaderboards
const highScoreSection = document.getElementById('high-scores');
descending.forEach((lb) => {
highScoreSection.appendChild(createLeaderboardLink(lb));
});
// Display low score leaderboards
const lowScoreSection = document.getElementById('low-scores');
ascending.forEach((lb) => {
lowScoreSection.appendChild(createLeaderboardLink(lb));
});
}
function createLeaderboardLink(leaderboard) {
const link = document.createElement('a');
link.href = `#/leaderboard/${leaderboard.leaderboardID}`;
link.textContent = leaderboard.leaderboardName;
return link;
}
Understanding Score Order
The leaderboardScoreOrder field determines how scores are ranked:
Descending Order (Value: 1)
Higher scores are better. Used for:
- Points-based games
- High score challenges
- Kill counts
- Distance traveled
- Coins collected
if (leaderboard.leaderboardScoreOrder === 1) {
console.log('This leaderboard ranks by highest score');
// Display: 1000 > 500 > 100
}
Ascending Order (Value: -1)
Lower scores are better. Used for:
- Time trials
- Speed runs
- Golf scores
- Number of moves
- Completion time
if (leaderboard.leaderboardScoreOrder === -1) {
console.log('This leaderboard ranks by lowest score');
// Display: 10 < 50 < 100
}
Error Handling
Handle errors when loading metadata:
MoitribeSDK('my-game-id', 'loadleaderboardmetadata', {
onlyData: true,
callback: (result) => {
if (result.success) {
if (result.leaderboards.length === 0) {
console.warn('No leaderboards configured for this game');
showMessage('No leaderboards available');
} else {
processLeaderboards(result.leaderboards);
}
} else {
console.error('Failed to load leaderboards:', result.msg);
showError('Unable to load leaderboards. Please try again later.');
}
}
});
Best Practices
1. Load Metadata Early
Load leaderboard metadata when your game starts:
// Load during game initialization
MoitribeSDK('my-game-id', 'init', {
loginCallback: (result) => {
if (result.success) {
// Load leaderboards after authentication
loadLeaderboardMetadata();
}
}
});
function loadLeaderboardMetadata() {
MoitribeSDK('my-game-id', 'loadleaderboardmetadata', {
onlyData: true,
callback: (result) => {
if (result.success) {
cacheMetadata(result.leaderboards);
}
}
});
}
2. Cache Metadata
Avoid repeated API calls by caching metadata:
// Good: Cache and reuse
let cachedLeaderboards = null;
function getLeaderboards(callback) {
if (cachedLeaderboards) {
callback(cachedLeaderboards);
return;
}
MoitribeSDK('my-game-id', 'loadleaderboardmetadata', {
onlyData: true,
callback: (result) => {
if (result.success) {
cachedLeaderboards = result.leaderboards;
callback(cachedLeaderboards);
}
}
});
}
3. Validate Metadata
Check that required fields exist:
function validateLeaderboardMetadata(leaderboard) {
return leaderboard &&
leaderboard.leaderboardID &&
leaderboard.leaderboardName &&
typeof leaderboard.leaderboardScoreOrder === 'number';
}
MoitribeSDK('my-game-id', 'loadleaderboardmetadata', {
onlyData: true,
callback: (result) => {
if (result.success) {
const valid = result.leaderboards.filter(validateLeaderboardMetadata);
console.log(`Loaded ${valid.length} valid leaderboards`);
}
}
});
4. Handle Missing Icons
Provide fallback for missing leaderboard icons:
function getLeaderboardIcon(leaderboard) {
return leaderboard.leaderboardIconURL || 'assets/default-leaderboard-icon.png';
}
Next Steps
- Get Top Scores - Retrieve leaderboard rankings
- Submit Score - Post player scores
- Score Collections - Understanding Social vs Global
- Best Practices - Leaderboard implementation tips
Related topics:
- Leaderboards Overview - Complete leaderboard guide
- API Reference - Full method documentation