Skip to content

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

GetLeaderboard GetLeaderboard

When the leaderboard data is loaded, the onLeaderboardsLoaded function is triggered.

On function onLeaderboardsLoaded
    → leaderboardData

GetLeaderboard

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

GetLeaderboard

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

GetScores GetScores

When the scores data is loaded, the onScoresLoaded function is triggered.

On function onScoresLoaded
    → ScoreData

GetScores

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

SubmitScores SubmitScores

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

ShowLeaderboard 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 highest to false when 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.