Leaderboards
The Y8 SDK allows your game to retrieve leaderboard tables and scores, submit player scores, and display leaderboards.
Select your engine below to view the appropriate implementation.
Get Leaderboards
Retrieve the leaderboard tables configured for your application.
y8Sdk.getLeaderboards()
.then((tables) => {
console.log(tables);
})
.catch((error) => {
console.error(error.message ?? error);
});
The result is an array of table names, in the order set in the Developer
Portal — for example ["level_1", "level_2"].
To retrieve leaderboards from another game:
y8Sdk.getLeaderboards("otherAppId")
.then((tables) => {
console.log(tables);
})
.catch((error) => {
console.error(error.message ?? error);
});
An empty array indicates that no leaderboard tables have been configured.
JsResponse<ScoreTables> response =
await Y8.Instance.GetLeaderboardsAsync();
if (response.IsSuccess)
{
Debug.Log(response.Data);
}
If no leaderboard tables have been configured, the returned collection is empty.
GetLeaderboard → On clicked
→ Call getLeaderboards

When the leaderboard data is loaded, the onLeaderboardsLoaded function is triggered.
On function onLeaderboardsLoaded
→ leaderboardData

The leaderboard data is provided as a JSON string: the same array of table names as in JavaScript, or an empty string if the request failed.
To retrieve leaderboards from another game:
GetLeaderboard → On clicked
→ Call getLeaderboards

Y8.getLeaderboards(function(leaderboards:Dynamic) {
if (leaderboards == null) {
trace("Failed to get leaderboards");
return;
}
trace(haxe.Json.stringify(leaderboards, null, " "));
});
The callback receives the available leaderboard tables.
If the request fails, the callback receives null.
Get Leaderboard Scores
Retrieve scores from a leaderboard.
y8Sdk.getLeaderboardScores({
table: "level_1",
page: 1,
perPage: 10,
mode: "alltime",
highest: true,
playerId: null,
appId: null
})
.then((scores) => {
console.log(scores);
})
.catch((error) => {
console.error(error.message ?? error);
});
Parameters
| Property | Type | Required | Description |
|---|---|---|---|
table |
string |
Yes | Leaderboard table name. |
page |
number |
No | Page number. Default: 1. |
perPage |
number |
No | Number of results per page. Default: 10. |
mode |
string |
No | Time period: alltime (default), last30days, last7days, today (the last 24 hours), or newest (most recently updated first; highest is ignored). Periods are rolling windows over each score's lastupdated. |
highest |
boolean |
No | Set to false when lower scores are better. Default: true. |
playerId |
string |
No | Retrieve scores for a specific player. |
appId |
string |
No | Retrieve scores from another game. |
Result
A page of scores, not a bare array:
{
page: 1,
perPage: 10,
totalPages: 1000,
items: [ /* Score objects */ ]
}
totalPages is not a real count: it is always Math.ceil(10000 / perPage).
To find the last page, check whether items.length < perPage.
Each entry in items:
| Property | Type | Description |
|---|---|---|
playername |
string |
Name shown on the board. Profanity is masked with *. |
points |
number |
The score. |
rank |
number |
Position in this result: (page - 1) * perPage + index + 1. With playerId it counts only that player's entries, so their best is always 1. With mode: "newest" it is the position by recency. |
playerid |
string |
Player identifier. |
scoreid |
string |
Identifier for this score entry. |
table |
string |
Name of the board this score belongs to. |
tableid |
string |
Internal identifier of that board. |
appid |
string |
The game it was set in. |
lastupdated |
number |
When the score was last set or improved, in Unix seconds. |
rdate |
string |
lastupdated formatted for display, for example "Oct. 2 2026". |
date |
number |
Not the time the score was set. Use lastupdated. |
source |
string |
"backend" on scores submitted server-side rather than through the SDK. Absent otherwise. |
An empty items array means the board exists but has no scores yet — not an
error.
JsResponse<ScoreTable> response =
await Y8.Instance.GetLeaderboardScoresAsync(
"level_1",
"alltime",
20,
1,
true
);
if (response.IsSuccess)
{
Debug.Log(response.Data);
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
table |
string |
Yes | Leaderboard table name. |
mode |
string |
No | Time period: alltime, last30days, last7days, today, or newest. Default: alltime. |
perPage |
int |
No | Number of results per page. Default: 20. |
page |
int |
No | Page number. Default: 1. |
highest |
bool |
No | Set to false when lower scores are better. Default: true. |
playerid |
string |
No | Retrieve scores for a specific player. |
Result
response.Data is a ScoreTable with items (a Score[]), page,
perPage and totalPages. As in JavaScript, totalPages is always
Math.ceil(10000 / perPage); check items.Length < perPage to find the
last page.
Each Score has table, playerid, playername, points (an int),
rank, date, rdate and scoreid, with the meanings given in the
JavaScript tab. date is not the time the score was set, so display rdate.
GetScores → On clicked
→ Call getScores

When the scores data is loaded, the onScoresLoaded function is triggered.
On function onScoresLoaded
→ ScoreData

The score data is provided as a JSON string of the same page object as in
JavaScript — page, perPage, totalPages and items — or an empty
string if the request failed.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
table |
string |
Yes | Leaderboard table name. |
page |
number |
No | Page number. Default: 1. |
perPage |
number |
No | Number of results per page. Default: 10. |
mode |
string |
No | Time period. Default: alltime. |
highest |
boolean |
No | Set to false when lower scores are better. |
playerId |
string |
No | Retrieve scores for a specific player. |
appId |
string |
No | Application ID for another game. |
Y8.getScores(
"level_1",
1,
10,
"alltime",
true,
function(scores:Dynamic) {
if (scores == null) {
trace("Failed to get scores");
return;
}
trace(haxe.Json.stringify(scores, null, " "));
}
);
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
table |
String |
Yes | Leaderboard table name. |
page |
Int |
Yes | Page number, starting at 1. |
perPage |
Int |
Yes | Number of results per page. |
mode |
String |
Yes | Time period: alltime, last30days, last7days, today, or newest. |
highest |
Bool |
Yes | Set to false when lower scores are better. |
callback |
Dynamic -> Void |
Yes | Called with the same page object as in JavaScript (page, perPage, totalPages, items), or null if the request failed. |
Save a Score
Submit a player's score to a leaderboard.
y8Sdk.saveLeaderboardScore({
table: "level_1",
points: 1500,
allowDuplicates: false,
highest: true,
playerName: null
})
.then(() => {
console.log("Score submitted");
})
.catch((error) => {
console.error(error.message ?? error);
});
Parameters
| Property | Type | Required | Description |
|---|---|---|---|
table |
string |
Yes | Leaderboard table name. |
points |
number |
Yes | Player score. 0 is rejected, and so is a score past the table's limit set in the Developer Portal. |
allowDuplicates |
boolean |
No | Has no effect: the server keeps one score per player per table, whichever is better. Default: false. |
highest |
boolean |
No | Set to false if lower scores are better. Default: true. |
playerName |
string |
No | Player name to display. Defaults to the authenticated player's nickname. A name you pass may use only letters, digits, _ and ., up to 20 characters. |
Errors
| Code | Meaning |
|---|---|
201 |
The player name contains characters other than letters, digits, _ and ., or is longer than 20 characters. |
207 |
No table with that name exists. |
208 |
The player is banned from this game's leaderboards. |
210 |
points is 0, or past the table's limit. |
211 |
This game accepts scores only when they are submitted server-side, not through the SDK. |
212, 213, 214 |
This game requires a signed-in player, and the player's access token was missing, invalid, or belonged to a different player. |
If no player is signed in, the call rejects with a plain string rather than an error object — see "Two different failure shapes" under Handling errors.
int score = 3001;
JsResponse<ScoreSave> response =
await Y8.Instance.SaveLeaderboardScoreAsync(
"level_1",
score,
false,
true
);
if (response.IsSuccess)
{
Debug.Log("Score submitted");
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
table |
string |
Yes | Leaderboard table name. |
points |
int |
Yes | Player score. |
allowduplicates |
bool |
No | Has no effect: the server keeps one score per player per table, whichever is better. Default: false. |
highest |
bool |
No | Set to false if lower scores are better. Default: true. |
SubmitScores → On clicked
→ Call submitScore

Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
table |
string |
Yes | Leaderboard table name. |
score |
number |
Yes | Player score. |
duplicate |
boolean |
No | Has no effect: the server keeps one score per player per table, whichever is better. Default: true. |
highest |
boolean |
No | Set to false when lower scores are better. |
playerName |
string |
No | Player name to display. |
Y8.saveScore(
"level_1",
1500,
false,
true
);
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
table |
String |
Yes | Leaderboard table name. |
points |
Int |
Yes | Player score. |
allowDuplicates |
Bool |
Yes | Has no effect: the server keeps one score per player per table, whichever is better. |
highest |
Bool |
Yes | Set to false if lower scores are better. |
Note
Submitting a score that is not better than the player's existing one — lower when highest is true, higher when it is false — does not generate an error. The request succeeds, but the leaderboard remains unchanged.
Display the Leaderboard
Display the built-in leaderboard interface.
y8Sdk.showLeaderboard();
You can also specify options:
y8Sdk.showLeaderboard({
table: "level_1",
mode: "alltime",
highest: true,
useMilli: false
});
The returned Promise resolves when the player closes the leaderboard.
Options
| Property | Type | Required | Description |
|---|---|---|---|
table |
string |
No | Leaderboard table to display. Defaults to the first table, which is also shown when the name does not match one. |
mode |
string |
No | Time period shown first; the player can switch it. Default: alltime. |
highest |
boolean |
No | Whether higher scores rank first. Default: true. |
useMilli |
boolean |
No | Treat scores as milliseconds and display them as MM:SS.mmm time values. Default: false. |
await Y8.Instance.ShowLeaderboardAsync(
"level_1",
"alltime",
true,
false
);
Debug.Log("Leaderboard closed");
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
tableTitle |
string |
Yes | Leaderboard table to display. A name that does not match a table shows the first one. |
mode |
string |
No | Time period shown first; the player can switch it. Default: alltime. |
highest |
bool |
No | Whether higher scores rank first. Default: true. |
useMilli |
bool |
No | Treat scores as milliseconds and display them as MM:SS.mmm time values. Default: false. |
ShowLeaderboard → On clicked
→ Call ShowLeaderboard

Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
table |
string |
No | Leaderboard table to display. Defaults to the first table, which is also shown when the name does not match one. |
mode |
string |
No | Time period shown first; the player can switch it. Default: alltime. |
highest |
boolean |
No | Whether higher scores rank first. Default: true. |
useMilli |
boolean |
No | Treat scores as milliseconds and display them as MM:SS.mmm time values. Default: false. |
Y8.showLeaderboard(
"level_1",
"alltime",
true
);
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
table |
String |
Yes | Leaderboard table to display. |
mode |
String |
Yes | Time period shown first; the player can switch it. |
highest |
Bool |
Yes | Whether higher scores rank first. |
Embed a leaderboard
Instead of the full-screen panel, you can place a leaderboard inside your own interface — a sidebar, a results screen, a menu tab.
const leaderboard = y8Sdk.embedLeaderboard({
target: "#leaderboard-panel",
table: "level_1",
mode: "alltime",
highest: true,
useMilli: false
});
Remove it when you are done with it:
leaderboard.destroy();
| Property | Type | Required | Description |
|---|---|---|---|
target |
string \| HTMLElement |
Yes | Container element, or a CSS selector for one. |
table |
string |
No | Leaderboard table to show. Defaults to the first table, which is also shown when the name does not match one. |
mode |
string |
No | Time period shown first; the player can switch it. Default: alltime. |
highest |
boolean |
No | Whether higher scores rank first. Default: true. |
useMilli |
boolean |
No | Treat scores as milliseconds and show them as MM:SS.mmm times rather than numbers. Default: false. |
Give the container a size
The embedded leaderboard fills its container's width and height. If the container has no dimensions of its own it collapses and nothing appears.
Embed after sign-in has been reported
The embed is created immediately, using whichever Y8 site the player came from. Very early in startup that is not yet known, so embedding in your first frame can point the panel at the default site instead of the player's own.
Creating it once authentication has been reported avoids this. The full-screen panel is unaffected — it waits on its own.
Not available on this platform. Use the full-screen leaderboard described above.
The event sheet has no function for this, so call embedLeaderboard()
from a script action. It takes no arguments and always embeds this
configuration, which is written in main.js — edit the values there to
suit your game:
embeddedLB = y8Sdk.embedLeaderboard({
target: "#leaderboard-panel",
table: "level_1",
mode: "alltime",
highest: true
});
The page needs an HTML element with the id leaderboard-panel. Remove the
leaderboard with destroyLeaderboard().
The container needs explicit dimensions, or the panel collapses to nothing.
Not available on this platform. Use the full-screen leaderboard described above.
Best Practices
- Retrieve available leaderboard tables before requesting scores.
- Verify leaderboard table names before submitting scores.
- Submit scores after the relevant gameplay has been completed.
- Set
highesttofalsewhen lower scores represent better results. - Handle asynchronous errors appropriately for your engine.
- Use the built-in leaderboard interface for a quick platform experience.
- Use the embedded leaderboard when integrating it into your own JavaScript UI.