Skip to main content

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.

info

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

ParameterTypeRequiredDescription
onlyDatabooleanYesSet to true to get data programmatically
callbackfunctionYesCalled with the result
tip

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

Related topics: