Skip to main content
Version: v3

Leaderboard Guide

info

Before continuing, make sure you have read:

  • Leaderboard Introduction. It introduces the core concepts and functions of Leaderboard.
  • TDS Authentication Guide. There are three types of members: user, object, and entity. Here “user” refers to the users in the built-in account system. Besides, the currentUser mentioned later in this page refers to the currently logged-in user.

Installing and Setting up SDK

Leaderboard comes as a part of the Data Storage SDK. Check the following pages if you haven’t set up the Data Storage SDK.

Quick Start

Creating Leaderboards

There are 3 ways to create a leaderboard:

For example, you can create a leaderboard named world with “built-in account system” as the type of members, descending as the order, better as the update strategy, and “every month” as the reset interval.

create leaderboard

Submitting Scores

If the player is logged in (accessible with currentUser), you can update their score with the following code:

var statistic = new Dictionary<string, double>();
statistic["world"] = 20.0;
await LCLeaderboard.UpdateStatistics(currentUser, statistic);

Getting Results

The code below retrieves the top 10 players from the leaderboard. Since we’ve only submitted one player’s score so far, the leaderboard will only have this one score.

var leaderboard = LCLeaderboard.CreateWithoutData("world");
var rankings = await leaderboard.GetResults(limit: 10);

We’ve just introduced the most basic usage of Leaderboard. Now let’s look at all the interfaces provided by Leaderboard.

Managing Scores

Updating the Current Player’s Scores

Once a player finishes a game, you can use the updateStatistic method provided by the client SDK to update this player’s score. However, to effectively prevent cheating from happening, we suggest that you enable “Only Master Key is allowed to update the score” on the dashboard and update scores on the server side only.

var statistic = new Dictionary<string, double> {
{ "score", 3458.0 },
{ "kills", 28.0 }
};
await LCLeaderboard.UpdateStatistics(currentUser, statistic);

Updating a player’s score requires this player to be logged in. A player can only update their own scores. You can update multiple leaderboards at once. The example above updates the scores in both score and kills.

You cannot update an object or entity’s scores with the client SDK. To update other players’, an object’s, or an entity’s scores, you have to use the REST API or the management interface provided by the SDK.

Deleting the Current Player’s Scores

A player can delete their own scores:

await LCLeaderboard.DeleteStatistics(currentUser, new List<string> { "world" });

Same as updating scores, a player can only delete their own scores. To delete other players’, an object’s, or an entity’s scores, you have to use the REST API or the management interface provided by the SDK.

Getting Leaderboard Members’ Scores

A logged-in player can retrieve the scores of other players in all leaderboards with GetStatistics:

var otherUser = LCObject.CreateWithoutData(TDSUser.CLASS_NAME, "5c76107144d90400536fc88b");
var statistics = await LCLeaderboard.GetStatistics(otherUser);
foreach(var statistic in statistics) {
Debug.Log(statistic.Name);
Debug.Log(statistic.Value);
}

In most cases, you may only need to retrieve the scores of a user from specific leaderboards. To do so, provide the names of the leaderboards when querying:

var statistics = await LCLeaderboard.GetStatistics(otherUser, new List<string> { "world" });

Similarly, you can retrieve scores from leaderboards with member types being object or entity.

For example, if the weapon leaderboard has its member type to be object:

var excalibur = LCObject.createWithoutData("Weapon", "582570f38ac247004f39c24b");
var statistics = await LCLeaderboard.GetStatistics(excalibur, new List<string> { "weapons" });

If the weapon leaderboard has its member type to be entity:

var statistics = await LCLeaderboard.GetStatistics("excalibur", new List<string> { "weapons" });

You can also retrieve the scores of a group of members:

var otherUser = LCObject.CreateWithoutData(TDSUser.CLASS_NAME, "5c76107144d90400536fc88b");
var anotherUser = LCObject.CreateWithoutData(TDSUser.CLASS_NAME, "672a127144a90d00536f3456");
var statistics = await LCLeaderboard.GetStatistics({otherUser, anotherUser}, new List<string> { "world" });

var oneObject = LCObject.CreateWithoutData<LCObject>("abccb27133a90ddd536ffffa");
var anotherUser = LCObject.CreateWithoutData<LCObject>("672a1279345777005a2b2444");
var statistics = await LCLeaderboard.GetStatistics({oneObject, anotherObject}, new List<string> { "weapons" });

var statistics = await LCLeaderboard.GetStatistics({"Sylgr", "Leiptr"}, new List<string> { "rivers" });

Getting Leaderboard Results

You can get the result of a leaderboard with the Leaderboard#getResults method. The most common use case of it is to get the scores of the top players or to get the players with similar rankings as the current player.

Let’s first construct a leaderboard instance:

var leaderboard = LCLeaderboard.CreateWithoutData("world");

LCLeaderboard.CreateWithoutData accepts two arguments:

public static LCLeaderboard CreateWithoutData(string statisticName, string memberType = LCLeaderboard.USER_MEMBER_TYPE)
  • statisticName is the name of an existing leaderboard. It’s set to be world in the example above.
  • memberType is the type of members: LCLeaderboard.USER_MEMBER_TYPE for user and LCLeaderboard.ENTITY_MEMBER_TYPE for entity. For object, provide the corresponding class name. The example above omitted this argument, which means to default to user.

After the leaderboard instance is constructed, you can call the corresponding methods on the instance to get the rankings.

Getting Rankings Within a Scope

To get the top 10 on the leaderboard:

var rankings = await leaderboard.GetResults(limit: 10);

GetResults accepts the following arguments for specifying constraints:

NameTypeDescription
aroundUserLCUserGet the players with similar rankings as a given player. See the next section for more information.
aroundObjectLCObjectGet the objects with similar rankings as a given object. See the next section for more information.
aroundEntitystringGet the entities with similar rankings as a given entity. See the next section for more information.
limitnumberLimit the number of results. Defaults to 10.
skipnumberSet the offset. Can be used with limit to implement pagination. Defaults to 10.
selectKeysstring[]Specify the properties that need to be included with the users from the returned Rankings. Continue reading for more information.
includeKeysstring[]Specify the Pointer properties that need to be included with the users from the returned Rankings. Continue reading for more information.
includeStatisticsstring[]Specify the scores in other leaderboards that need to be included in the Rankings. Continue reading for more information.
versionnumberSpecify the version of the leaderboard.

The returned result is an array (Ranking[]) with each Ranking holding the following properties:

NameTypeDescription
RankintThe ranking. Starts with 0.
UserLCUserThe user who got the score (for user leaderboards).
ObjectLCObjectThe object who got the score (for object leaderboards).
EntitystringThe entity who got the score (for entity leaderboards).
ValuedoubleThe score.
IncludedStatisticsList<Statistic>The member’s scores in other leaderboards.

By default, the users in the results are LCUser Pointers. To include the usernames or other properties (in the _User class) of the users so that they can be displayed like the table below, specify them with selectKeys.

RankingUsernameScore↓
0Genji3458
1Lúcio3252
2D.Va3140
var rankings = await leaderboard.GetResults(limit: 10,
selectKeys: new List<string> { "username" });

To include the players’ scores in other leaderboards, use includeStatistics. For example, to include the kills when retrieving the leaderboard for scores:

RankingUsernameScore↓Kills
0Genji345828
1Lúcio32522
2D.Va314031
var rankings = await leaderboard.GetResults(limit: 10, selectKeys: new List<string> { "username" }
includeStatistics: new List<string> { "kills" });

If a Pointer or file property is included using selectKeys, you will only get the Pointers themselves. To include the objects referenced by the Pointers, you need to use includeKeys as well. For example, assuming club is a Club Pointer:

var leaderboard = LCLeaderboard.CreateWithoutData("weapons", "Weapon");
var rankings = await leaderboard.GetResults(limit: 10,
selectKeys: new List<string> { "name", "club" },
includeKeys: new List<string> { "club" });

Keep in mind that the order of the members with the same score in the returned result is not guaranteed. For example, if A, B, and C got 42, 32, and 32, and the leaderboard has a descending order, the result might list the three members in the order of either “A, B, C” or “A, C, B”.

When the score is the same, if you need other factors to set the ranking, you can refer to the following example (example is to judge the ranking by the time stamp of the score upload, when the score is the same, the earlier/later the submission, the higher/lower the ranking) :

Android request example:
public class RankingActivity extends AppCompatActivity{

// ...

/**
* Upload/update grades
*
* */
private void submitScore() {

double score = 324.45; // Actual score
long ts = System.currentTimeMillis() / 1000; // time stamp
double last_score = toEncode( score, ts); // Combine the actual score with the timestamp to generate a new data upload to the server

Map<String, Double> statistic = new HashMap<>();
statistic.put("word", last_score);

LCLeaderboard.updateStatistic(LCUser.currentUser(), statistic).subscribe(new Observer<LCStatisticResult>() {
@Override
public void onSubscribe(@NotNull Disposable disposable) {}

@Override
public void onNext(@NotNull LCStatisticResult jsonObject) {
Log.e(TAG, "onNext: "+jsonObject.getResults().get(0).toString());

}

@Override
public void onError(@NotNull Throwable throwable) {
ToastUtil.showCus(throwable.getMessage(), ToastUtil.Type.ERROR);
}

@Override
public void onComplete() {}
});

}

/**
* 查询排行榜列表
* */
private void searchRankList() {
// Obtain an instance of a leaderboard
LCLeaderboard leaderboard = LCLeaderboard.createWithoutData("word");

leaderboard.getResults(0, 10, null, null).subscribe(new Observer<LCLeaderboardResult>() {
@Override
public void onSubscribe(@NotNull Disposable disposable) {}

@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onNext(@NotNull LCLeaderboardResult leaderboardResult) {
List<LCRanking> rankings = leaderboardResult.getResults();
for(int i=0; i<rankings.size(); i++){
/**
* Decrypt the query method
*/
double score = rankings.get(i).getStatisticValue(); // Obtain the scores found in the query
String formatScore = String.format("%.3f", score); // Serialize fractions of type double into a string that retains 3 decimal places
BigDecimal decimalValue = new BigDecimal(formatScore);
long longPart = decimalValue.longValue(); // Obtain the integer part of the StatisticValue found in the query
float floatPart = decimalValue.subtract(BigDecimal.valueOf(longPart)).floatValue(); // Obtain the decimal part of the StatisticValue found in the query

int[] decryptedScoreTs = toDecode(longPart); // Decrypt the integer part
int decryptedScore = decryptedScoreTs[0]; // Obtain the integer part of the actual score
long decryptedTs = decryptedScoreTs[1]; // Obtain the timestamp when submitting grades

BigDecimal bigDecimalValue = new BigDecimal(Integer.toString(decryptedScore))
.add(new BigDecimal(Float.toString(floatPart))); // Splice the integer part of the actual score with the decimal part to obtain the actual score
double doubleValue = bigDecimalValue.doubleValue(); // Convert actual scores to double type

Log.e(TAG, "Parsed score: "+doubleValue+" Parsed timestamp:"+ decryptedTs );

}

}

@Override
public void onError(@NotNull Throwable throwable) {
}

@Override
public void onComplete() {}
});

}

/**
* score: Actual score
* ts: time stamp
* Combine the actual score with the timestamp to generate a new data upload to the server
*/
public static double toEncode(double score, long ts) {
int int_score = (int) score; // The integer part of the actual score

float float_score = (float) (score - int_score); // Decimal portion of actual score

/**
* When the leaderboard is arranged in descending order and the scores are the same, the closer the time, the higher the ranking. Use this line of code
*/
// long encryptedScoreTs = ((long) int_score << 32) | (ts & 0xFFFFFFFFL); // Encrypt and merge integer fractions with timestamps to form a new score


/**
* When the leaderboard is arranged in descending order and the scores are the same, the closer the time and the lower the ranking, use this line of code
*/
long encryptedScoreTs = ((long) int_score << 32) - (ts & 0xFFFFFFFFL); // Encrypt and merge integer fractions with timestamps to form a new score

double newScore = (double)encryptedScoreTs + float_score; // Then concatenate the encrypted generated data with decimal parts of the data and upload it to the server
return newScore;
}

/**
* Parse the encrypted data to determine the actual score and the timestamp when submitting the score at that time
*
*/
public static int[] toDecode(long encryptedNewScore) {
/**
* When the leaderboard is arranged in descending order and the scores are the same, the closer the time, the higher the ranking. Use this line of code
*/

// int score = (int) (encryptedNewScore >> 32);

/**
* When the leaderboard is arranged in descending order and the scores are the same, the closer the time and the lower the ranking, use this line of code
*/
int score = (int) (encryptedNewScore >> 32) + 1;
long ts = encryptedNewScore & 0xFFFFFFFFL;
return new int[]{score, (int) ts};
}

}

Getting the Players With Similar Rankings as the Current Player

RankingUsernameScore↓
24Bastion716
25 (You)Widowmaker698
26Hanzo23

To implement something like the table above in your game, provide the current user when calling GetResults:

var rankings = await leaderboard.GetResults(aroundUser: currentUser, limit: 3, selectKeys: new List<string> { "username" });

In the example above, the limit is set to 3, which means to get two players with similar rankings as the current player together with the current player placed between them. You can set limit to 1 to get the current player’s ranking only.

Similarly, you can retrieve objects or entities with similar rankings as a given object or entity. For example, to get the weapons with similar rankings as a given weapon from the weapon leaderboard, including their names, attacks, and levels:

var leaderboard = LCLeaderboard.CreateWithoutData("weapons", "Weapon");
var excalibur = LCObject.createWithoutData("Weapon", "582570f38ac247004f39c24b");
var rankings = await leaderboard.GetResults(aroundObject: excalibur, limit: 3, selectKeys: new List<string> { "name", "attack", "level" });

The example above assumes that the weapon leaderboard is an object leaderboard and the class for storing weapons is named Weapon. If the weapon leaderboard has entity as its type, and you only need to retrieve the names of the weapons, the following code would apply:

var leaderboard = LCLeaderboard.CreateWithoutData("weapons", LCLeaderboard.ENTITY_MEMBER_TYPE);
var rankings = await leaderboard.GetResults(aroundEntity: "excalibur", limit: 3);

Dashboard

On Game Services > Cloud Services > Leaderboard, you can:

  • Create, reset, edit, and delete leaderboards.
  • View the current versions of the leaderboards, delete scores, and download the archives of the earlier versions of the leaderboards.
  • Configure whether the client can retrieve the previous version of each leaderboard, and whether scores can be updated with the Master Key only.

SDK Management Interface

Besides using the dashboard, you can also manage leaderboards with the management interfaces provided by the C# SDK and the Java SDK. Those interfaces can be used in trusted environments including the server side. Another way to access the management interface is to use the REST API.

Let’s first take a look at the management interfaces provided by the SDKs.

caution

To use the management interface, the SDK needs to be initialized with the masterKey. Therefore, you should only use the management interface in trusted environments like the server side, and not the client side.

LCApplication.Initialize({{appid}}, {{appkey}}, "https://xxx.example.com", {{masterkey}});
LCApplication.UseMasterKey = true;

Creating Leaderboards

var leaderboard = await LCLeaderboard.CreateLeaderboard("time", order: LCLeaderboardOrder.ASCENDING);

Below are the available options and their default values:

public static async Task<LCLeaderboard> CreateLeaderboard(string statisticName,
LCLeaderboardOrder order = LCLeaderboardOrder.Descending,
LCLeaderboardUpdateStrategy updateStrategy = LCLeaderboardUpdateStrategy.Better,
LCLeaderboardVersionChangeInterval versionChangeInterval = LCLeaderboardVersionChangeInterval.Week,
string memberType = LCLeaderboard.USER_MEMBER_TYPE)
  • statisticName The name of the leaderboard.
  • order The order. Can be LCLeaderboardOrder.Descending or LCLeaderboardOrder.Ascending.
  • updateStrategy The strategy for updating scores. Can be LCLeaderboardUpdateStrategy.Better, LCLeaderboardUpdateStrategy.Last, or LCLeaderboardUpdateStrategy.Sum.
  • versionChangeInterval The interval for resetting the leaderboard. Can be LCLeaderboardVersionChangeInterval.Never, LCLeaderboardVersionChangeInterval.Day, LCLeaderboardVersionChangeInterval.Week, or LCLeaderboardVersionChangeInterval.Month.
  • memberType The type of the members. Use LCLeaderboard.USER_MEMBER_TYPE for user and LCLeaderboard.ENTITY_MEMBER_TYPE for entity. For object, use the name of the class.

Manually Resetting the Leaderboard

var leaderboard = LCLeaderboard.CreateWithoutData("score");
await leaderboard.Reset();

Retrieving Leaderboard Properties

Use the following interface to get the properties of a leaderboard, including its reset interval, version, and update strategy.

var leaderboardData = await LCLeaderboard.GetLeaderboard("world");

Updating Leaderboard Properties

Once a leaderboard is created, only its reset interval and update strategy can be updated. Other properties cannot be modified.

var leaderboard = LCLeaderboard.CreateWithoutData("equip");
await leaderboard.UpdateVersionChangeInterval(LCLeaderboardVersionChangeInterval.Week);
await leaderboard.UpdateUpdateStrategy(LCLeaderboardUpdateStrategy.Last);

Deleting Leaderboards

var leaderboard = lcleaderboard.createwithoutdata("equip");
await leaderboard.destroy();

Deleting a leaderboard will delete all the data within it, including the current version and the archives of the past versions.

Updating Leaderboard Members’ Scores

You can use the overwrite option to bypass the update strategy and force update a member’s score:

var statistic = new Dictionary<string, double> {
{ "score", 0.0 }
};
await LCLeaderboard.UpdateStatistics(user, statistic, overwrite: true);

Object and entity leaderboards can only be updated on the server side with the Master Key. The update strategy of the leaderboard will still be followed, though:

var excalibur = LCObject.createWithoutData("Weapon", "582570f38ac247004f39c24b");
await LCLeaderboard.UpdateStatistics(excalibur, statistic);

To force update the data, set overwrite to true:

await LCLeaderboard.UpdateStatistics("Vimur", statistic, overwrite: true);

Deleting Leaderboard Members’ Scores

Use the Master Key on the server side to delete the score of any user, object, or entity:

var otherUser = LCObject.CreateWithoutData(TDSUser.CLASS_NAME, "5c76107144d90400536fc88b");
await LCLeaderboard.DeleteStatistics(otherUser, new List<string> { "world" });

var excalibur = LCObject.createWithoutData("Weapon", "582570f38ac247004f39c24b");
await LCLeaderboard.DeleteStatistics(excalibur, new List<string> { "weapons" });

await LCLeaderboard.DeleteStatistics("Vimur", new List<string> { "rivers" });

REST API

Now we will introduce the Leaderboard-related REST API interfaces. You can write your own programs or scripts to access these interfaces to perform administrative operations on the server side.

Request Format

For POST and PUT requests, the body of the request must be in JSON, and the Content-Type of the HTTP Header should be application/json.

Requests are authenticated by the following key-value pairs in the HTTP Header:

KeyValueMeaningSource
X-LC-Id{{appid}}The App Id (Client Id) of the current appCan be found on the Developer Center
X-LC-Key{{appkey}}The App Key (Client Token) of the current appCan be found on the Developer Center

To access the management interface, the Master Key is required: X-LC-Key: {{masterkey}},master. Master Key is also named Server Secret, which can be found on the Developer Center as well.

See Credentials for more information.

Base URL

The Base URL for the REST API ({{host}} in curl examples) is the app’s custom API domain, which can be added and viewed on the Developer Center. See Domain for more information.

Managing Leaderboards

Creating Leaderboards

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '{"statisticName": "world", "memberType": "_User", "order": "descending", "updateStrategy": "better", "versionChangeInterval": "month"}' \
https://{{host}}/1.1/leaderboard/leaderboards
ParameterRequiredDescription
statisticNameRequiredThe name of the leaderboard. Cannot be edited once the leaderboard is created.
memberTypeRequiredThe type of the members. Cannot be edited once the leaderboard is created. Can be _Entity, _User, or the name of an existing class.
orderOptionalThe strategy for ordering. Cannot be edited once the leaderboard is created. Can be ascending or descending. Defaults to descending.
updateStrategyOptionalCan be better, last, or sum. Defaults to better.
versionChangeIntervalOptionalCan be day, week, month, or never. Defaults to week.

The response body will be a JSON object containing all the parameters provided when creating the leaderboard, as well as the following fields:

  • version The version of the leaderboard.
  • expiredAt The time the leaderboard will be reset for the next time.
  • activatedAt The time the current version started.
{
"objectId": "5b62c15a9f54540062427acc",
"statisticName": "world",
"memberType": "_User",
"versionChangeInterval": "month",
"order": "descending",
"updateStrategy": "better",
"version": 0,
"createdAt": "2018-08-02T08:31:22.294Z",
"updatedAt": "2018-08-02T08:31:22.294Z",
"expiredAt": {
"__type": "Date",
"iso": "2018-08-31T16:00:00.000Z"
},
"activatedAt": {
"__type": "Date",
"iso": "2018-08-02T08:31:22.290Z"
}
}

Retrieving Leaderboard Properties

The following interface allows you to retrieve the properties of a leaderboard, including its update strategy and version number.

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
https://{{host}}/1.1/leaderboard/leaderboards/<statisticName>

The returned JSON object contains all the information related to the leaderboard:

{
"objectId": "5b0b97cf06f4fd0abc0abe35",
"statisticName": "world",
"memberType": "_User",
"order": "descending",
"updateStrategy": "better",
"version": 5,
"versionChangeInterval": "day",
"expiredAt": { "__type": "Date", "iso": "2018-05-02T16:00:00.000Z" },
"activatedAt": { "__type": "Date", "iso": "2018-05-01T16:00:00.000Z" },
"createdAt": "2018-04-28T05:46:58.579Z",
"updatedAt": "2018-05-01T01:00:00.000Z"
}

Updating Leaderboard Properties

The following interface allows you to update the updateStrategy and versionChangeInterval of a leaderboard. Properties other than these cannot be updated. You can update only one of the two properties. For example, to update versionChangeInterval only:

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '{"versionChangeInterval": "day"}' \
https://{{host}}/1.1/leaderboard/leaderboards/<statisticName>

The returned JSON object contains all the updated fields as well as an updatedAt field.

{
"objectId": "5b0b97cf06f4fd0abc0abe35",
"versionChangeInterval": "day",
"updatedAt": "2018-05-01T08:01:00.000Z"
}

Resetting Leaderboards

The following interface allows you to reset a leaderboard regardless of its reset strategy. Once you reset a leaderboard, the current version of it will be cleared and the cleared data will be archived as a CSV file for you to download. The version of the leaderboard will automatically increment by 1.

curl -X PUT \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
https://{{host}}/1.1/leaderboard/leaderboards/<statisticName>/incrementVersion

The returned JSON object will contain the new version number, the time the leaderboard will be reset for the next time (expiredAt), and the time the current version started (activatedAt):

{
"objectId": "5b0b97cf06f4fd0abc0abe35",
"version": 7,
"expiredAt": { "__type": "Date", "iso": "2018-06-03T16:00:00.000Z" },
"activatedAt": { "__type": "Date", "iso": "2018-05-28T06:02:56.169Z" },
"updatedAt": "2018-05-28T06:02:56.185Z"
}

Retrieving Archives

Since each leaderboard can hold at most 60 archive files, we recommend that you retrieve the archived files regularly and back them up in your own places with the following interface.

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-G \
--data-urlencode 'limit=10' \
https://{{host}}/1.1/leaderboard/leaderboards/<statisticName>/archives

The returned objects will be in decreasing order by createdAt. For each object, it has the file name (file_key), the URL for downloading (url), and a status property being one of the following statuses:

  • scheduled: The archiving process is queued. This usually won’t last very long.
  • inProgress: Archiving in progress.
  • failed: Failed to archive. Please reach out to our technical support.
  • completed: Successfully archived.
{
"results": [
{
"objectId": "5b0b9da506f4fd0abc0abe6e",
"statisticName": "wins",
"version": 9,
"status": "completed",
"url": "https://lc-paas-files.cn-n1.lcfile.com/yK5s6YJztAwEYiWs.csv",
"file_key": "yK5s6YJztAwEYiWs.csv",
"activatedAt": { "__type": "Date", "iso": "2018-05-28T06:11:49.572Z" },
"deactivatedAt": { "__type": "Date", "iso": "2018-05-30T06:11:49.951Z" },
"createdAt": "2018-05-01T16:00.00.000Z",
"updatedAt": "2018-05-28T06:11:50.129Z"
}
]
}

Deleting Leaderboards

This will delete everything within the leaderboard, including the current version and all the archives. You won’t be able to undo this operation.

Provide the statisticName of the leaderboard to delete it.

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
https://{{host}}/1.1/leaderboard/leaderboards/<statisticName>

Once done, an empty JSON object will be returned:

{}

Managing Scores

Updating Scores

Use the Master Key to update any score while still following the updateStrategy.

Provide the corresponding user’s objectId when you update their score:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '[{"statisticName": "wins", "statisticValue": 5}, {"statisticName": "world", "statisticValue": 91}]' \
https://{{host}}/1.1/leaderboard/users/<objectId>/statistics

The returned data will be the current score:

{
"results": [
{
"statisticName": "wins",
"version": 0,
"statisticValue": 5
},
{
"statisticName": "world",
"version": 2,
"statisticValue": 91
}
]
}

Similarly, you can provide the objectId of an object when updating its score:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '[{"statisticName": "wins", "statisticValue": 5}, {"statisticName": "weapons","statisticValue": 91}]' \
https://{{host}}/1.1/leaderboard/objects/<objectId>/statistics

For entity, provide the string for it:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '[{"statisticName": "wins", "statisticValue": 5}, {"statisticName": "cities","statisticValue": 91}]' \
https://{{host}}/1.1/leaderboard/entities/<entityString>/statistics

The current user can update their own score, though this won’t require the Master Key for the management interface. However, the sessionToken of the current user needs to be provided (the SDK has already encapsulated this interface):

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "X-LC-Session: <sessionToken>" \
-H "Content-Type: application/json" \
-d '[{"statisticName": "wins", "statisticValue": 5}, {"statisticName": "world", "statisticValue": 91}]' \
https://{{host}}/1.1/leaderboard/users/self/statistics

Force Updating Scores

Add overwrite=1 to ignore the better and sum update strategies and use last instead. For example, if cheating is detected on a user, you can force update the user’s score with this interface.

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
-d '[{"statisticName": "wins", "statisticValue": 10}]' \
https://{{host}}/1.1/leaderboard/users/<uid>/statistics?overwrite=1

The returned data is the current score:

{ "results": [{ "statisticName": "wins", "version": 0, "statisticValue": 10 }] }

overwrite=1 can be used for object scores and entity scores as well.

Deleting Scores

Use this interface to remove the score and ranking of a user from the leaderboard. Note that only the score on the current version of the leaderboard can be removed.

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
-H "Content-Type: application/json" \
https://{{host}}/1.1/leaderboard/users/<uid>/statistics?statistics=wins,world

Once done, an empty object will be returned:

{}

Similarly, you can delete the score of an object:

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
--data-urlencode 'statistics=weapons,equipments' \
https://{{host}}/1.1/leaderboard/objects/<objectId>/statistics

And the score of an entity:

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{masterkey}},master" \
--data-urlencode 'statistics=cities' \
https://{{host}}/1.1/leaderboard/entities/<entityString>/statistics

The current user can delete their own score, though this won’t require the Master Key for the management interface. However, the sessionToken of the current user needs to be provided (the SDK has already encapsulated this interface):

curl -X DELETE \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "X-LC-Session: <sessionToken>" \
-H "Content-Type: application/json" \
https://{{host}}/1.1/leaderboard/users/self/statistics?statistics=wins,world

Retrieving Scores

The REST API interfaces for retrieving scores are not management interfaces and the Master Key is not required:

Retrieving a Single Score

Retrieve a score by providing the objectId of a user. You can specify multiple leaderboards within the statistics property (separated by ,) to get the scores of the user in all the given leaderboards. If this option is not provided, the user’s scores in all leaderboards will be returned.

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
--data-urlencode 'statistics=wins,world' \
https://{{host}}/1.1/leaderboard/users/<objectId>/statistics

Response:

{
"results": [
{
"statisticName": "wins",
"statisticValue": 5,
"version": 0,
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "60d950629be318a249000001"
}
},
{
"statisticName": "world",
"statisticValue": 91,
"version": 0,
"user": {...}
}
]
}

Similarly, you can get an object’s scores by providing its objectId:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
--data-urlencode 'statistics=wins,world' \
https://{{host}}/1.1/leaderboard/objects/<objectId>/statistics

Response:

{
"results": [
{
"statisticName": "wins",
"statisticValue": 5,
"version": 0,
"object": {
"__type": "Pointer",
"className": "Weapon",
"objectId": "60d1af149be3180684000002"
}
},
{
"statisticName": "world",
"statisticValue": 91,
"version": 0,
"object": {
"__type": "Pointer",
"className": "Weapon",
"objectId": "60d1af149be3180684000002"
}
}
]
}

To get an entity’s scores, provide the string for the entity:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
--data-urlencode 'statistics=wins,world' \
https://{{host}}/1.1/leaderboard/entities/<entityString>/statistics

Response:

{
"results": [
{
"statisticName": "wins",
"statisticValue": 5,
"version": 0,
"entity": "1a2b3c4d"
},
{
"statisticName": "world",
"statisticValue": 91,
"version": 0,
"entity": "1a2b3c4d"
}
]
}

Retrieving a Group of Scores

With this interface, you can get the scores of no more than 200 users at once. To use this interface, provide an array of objectIds of the users in the body.

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '["60d950629be318a249000001", "60d950629be318a249000000"]'
https://{{host}}/1.1/leaderboard/users/statistics/<statisticName>

The response is similar to that of retrieving a single score:

{
"results": [
{
"statisticName": "wins",
"statisticValue": 1,
"version": 0,
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "60d950629be318a249000001"
}
},
{
"statisticName": "wins",
"statisticValue": 2,
"version": 0,
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "60d950629be318a249000000"
}
}
]
}

Similarly, provide a list of objectIds of objects (no more than 200) to get these objects’ scores:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '["60d950629be318a249000001", "60d950629be318a249000000"]'
https://{{host}}/1.1/leaderboard/objects/statistics/<statisticName>

Provide a list of strings of entities (no more than 200) to get these entities’ scores:

curl -X POST \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-H "Content-Type: application/json" \
-d '["Vimur", "Fimbulthul"]'
https://{{host}}/1.1/leaderboard/entities/statistics/<statisticName>

Queries on Leaderboards

Retrieving Scores Within a Scope

Use this interface to retrieve the top players.

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'startPosition=0' \
--data-urlencode 'maxResultsCount=20' \
--data-urlencode 'selectKeys=username,club' \
--data-urlencode 'includeKeys=club' \
--data-urlencode 'includeStatistics=wins' \
https://{{host}}/1.1/leaderboard/leaderboards/user/<statisticName>/ranks
ParameterRequiredDescription
startPositionOptionalThe offset of the query. Defaults to 0.
maxResultsCountOptionalThe maximum number of results. Defaults to 20.
selectKeysOptionalReturn the other fields of the user in the _User class. You can provide multiple fields separated by ,. For security reasons, the email and mobilePhoneNumber fields will not be returned if you are not using the masterKey.
includeKeysOptionalReturn the referenced objects of the other fields of the user in the _User class. You can provide multiple fields separated by ,. For security reasons, the email and mobilePhoneNumber fields will not be returned if you are not using the masterKey.
includeStatisticsOptionalReturn the user’s scores in other leaderboards. If a non-existant leaderboard is provided, an error will be returned.
versionOptionalReturn the results from a specific version. By default, the results from the current version will be returned.
countOptionalIf set to 1, the number of members in the leaderboard will be returned. Defaults to 0.

The response will be a JSON object:

{
"results": [
{
"statisticName": "world",
"statisticValue": 91,
"rank": 0,
"user": {
"__type": "Pointer",
"className": "_User",
"updatedAt": "2021-07-21T03:08:10.487Z",
"username": "zw1stza3fy701rvgxqwiikex7",
"createdAt": "2020-09-04T04:23:04.795Z",
"club": {
"objectId": "60f78f98d9f1465d3b1da12d",
"name": "board games",
"updatedAt": "2021-07-21T03:08:08.692Z",
"createdAt": "2021-07-21T03:08:08.692Z",
},
"objectId": "5f51c1287628f2468aa696e6"
}
},
{...}
],
"count": 500
}

Querying on object leaderboards shares a similar interface. The only difference is that user will be replaced by object:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'startPosition=0' \
--data-urlencode 'maxResultsCount=2' \
--data-urlencode 'selectKeys=name,image' \
--data-urlencode 'includeKeys=image' \
--data-urlencode 'count=1' \
https://{{host}}/1.1/leaderboard/leaderboards/object/<statisticName>/ranks

Response:

{
"results": [
{
"statisticName": "wins",
"statisticValue": 4,
"rank": 0,
"object": {
"__type": "Pointer",
"className": "Weapon",
"name": "sword",
"image": {
"bucket": "test_files",
"provider": "leancloud",
"name": "sword.jpg",
"url": "https://example.com/sword.jpg",
"objectId": "60d2f3a39be3183377000002",
"__type": "File"
},
"objectId": "60d2f22f9be318328b000007"
}
},
{
"statisticName": "wins",
"statisticValue": 3,
"rank": 1,
"object": {...}
}
],
"count": 500
}

Change user to entity to query on entity leaderboards:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'startPosition=0' \
--data-urlencode 'maxResultsCount=2' \
--data-urlencode 'count=1' \
https://{{host}}/1.1/leaderboard/leaderboards/entity/<statisticName>/ranks

Response:

{
"results": [
{
"statisticName": "wins",
"statisticValue": 4,
"rank": 0,
"entity": "1234567890"
},
{
"statisticName": "wins",
"statisticValue": 3,
"rank": 1,
"entity": "2345678901"
}
],
"count": 500
}

Retrieving Members With Similar Rankings as the Given Member

Add the corresponding objectId to the end of the URL to retrieve the users and objects with similar rankings as the given one.

To get the users with similar rankings as the given user:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'startPosition=0' \
--data-urlencode 'maxResultsCount=20' \
--data-urlencode 'selectKeys=username,club' \
--data-urlencode 'includeKeys=club' \
https://{{host}}/1.1/leaderboard/leaderboards/user/<statisticName>/ranks/<objectId>

See Retrieving Scores Within a Scope for the meanings of the parameters. The response is similar to that for retrieving-scores-within-a-scope.

{
"results": [
{
"statisticName": "wins",
"statisticValue": 3,
"rank": 2,
"user": {...}
},
{
"statisticName": "wins",
"statisticValue": 2.5,
"rank": 3,
"user": {
"__type": "Pointer",
"className": "_User",
"username": "kate",
"club": {
"objectId": "60f78f98d9f1465d3b1da12d",
"name": "board games",
"updatedAt": "2021-07-21T03:08:08.692Z",
"createdAt": "2021-07-21T03:08:08.692Z",
},
"objectId": "60d2faa99be3183623000001"
}
},
{
"statisticName": "wins",
"statisticValue": 2,
"rank": 4,
"user": {...}
}
],
"count": 500
}

To get the objects with similar rankings as the given object:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'startPosition=0' \
--data-urlencode 'maxResultsCount=2' \
--data-urlencode 'selectKeys=name,image' \
--data-urlencode 'includeKeys=image' \
--data-urlencode 'count=1' \
https://{{host}}/1.1/leaderboard/leaderboards/object/<statisticName>/ranks/<objectId>

To get the entities with similar rankings as the given entity:

curl -X GET \
-H "X-LC-Id: {{appid}}" \
-H "X-LC-Key: {{appkey}}" \
-G \
--data-urlencode 'startPosition=0' \
--data-urlencode 'maxResultsCount=2' \
--data-urlencode 'count=1' \
https://{{host}}/1.1/leaderboard/leaderboards/entity/<statisticName>/ranks/<id>

Video Tutorials

You can refer to the video tutorial:How to Integrate Leaderboard in Games to learn how to access leaderboard in Untiy projects.

For more video tutorials, see Developer Academy. As the SDK features are constantly being improved, there may be inconsistencies between the video tutorials and the new SDK features, so the current documentation should prevail.