Leaderboards

The leaderboard system is flexible and allows learning apps to define custom leaderboards based on their needs.

Features

  • Categories & Subcategories: Use categoryId (e.g., skillId) to create leaderboards per skill, and optionally filter by subcategory (e.g., organizationId)
  • Flexible Units: Track any metric (points, seconds, stars, coins, etc.)
  • Sort Directions: Ascending (lower is better, for times) or descending (higher is better, for scores)
  • Weekly & Global Rankings: Each leaderboard maintains both weekly and all-time rankings

List Available Leaderboards

const res = await fetch(`${API_URL}/miscellaneous/v1/leaderboards`, {
  headers: { Authorization: `Bearer ${idToken}` },
});
const { leaderboards } = await res.json();
// Returns: [{ id: 'practice-scores', name: 'Top Scores', unit: 'points', sortDirection: 'desc' }, ...]

Current leaderboards:

  • practice-scores: Top scores (points, higher is better)
  • competition-times: Best times (seconds, lower is better)

Additional leaderboards can be defined as needed. Contact trashcat@trilogy.com to request new leaderboard configurations.

Submit a Score

// Example: Submit competition time
const totalTimeSeconds = activePlayTime + penaltyTime;
await fetch(
  `${API_URL}/miscellaneous/v1/leaderboards/competition-times/scores?categoryId=${skillId}&subcategory=${organizationId}`,
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${idToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      score: Math.round(totalTimeSeconds),
    }),
  },
);

Retrieve Rankings

Weekly Leaderboard

const weeklyRes = await fetch(
  `${API_URL}/miscellaneous/v1/leaderboards/competition-times/weekly/current?categoryId=${skillId}&subcategory=${organizationId}&limit=20`,
  {
    headers: { Authorization: `Bearer ${idToken}` },
  },
);
const { entries, currentUserEntry, totalCount } = await weeklyRes.json();

Global Leaderboard

const globalRes = await fetch(
  `${API_URL}/miscellaneous/v1/leaderboards/competition-times/global?categoryId=${skillId}&subcategory=${organizationId}&limit=20`,
  {
    headers: { Authorization: `Bearer ${idToken}` },
  },
);
const { entries, currentUserEntry, totalCount } = await globalRes.json();

Response Format

Both endpoints return:

{
  "entries": [
    { "rank": 1, "score": 180, "playerName": "Alice", "unit": "seconds" },
    { "rank": 2, "score": 195, "playerName": "Bob", "unit": "seconds" },
    // ... up to limit
  ],
  "currentUserEntry": {
    "rank": 47,
    "score": 240,
    "playerName": "CurrentUser",
    "unit": "seconds"
  },
  "totalCount": 156
}

Key fields:

  • entries: Top performers (limited by limit parameter)
  • currentUserEntry: Current user's ranking (included even if outside top entries)
  • totalCount: Total participants in this leaderboard

Leaderboard Scoping

Use categoryId and subcategory to create focused competitions:

School-level competition:

// Only students from the same organization compete
?categoryId=${skillId}&subcategory=${organizationId}

Global competition:

// All students compete (omit subcategory)
?categoryId=${skillId}

Skill-specific:

// Different leaderboards per skill
?categoryId=multiplication  // vs
?categoryId=division

Authentication setup required for accessing leaderboards and submitting scores.

Production code showing how to integrate leaderboard submissions into your learning session flow.

Complete endpoint documentation for leaderboard operations, including all query parameters and response schemas.