League and Division Leaderboards

This tutorial will demonstrate one way of creating Leaderboards that allocate users' entries based on what league and division they're placed in. Players will also be promoted and demoted depending on how well they did. By using Leaderboards, Events, Cloud Code, Schedulers, Segments, and player scriptData, we'll create a system that is both editable and simple.

Registration and League Placement

When a player in your game registers, their league segment needs to be initialized and they need to be assigned a placement status before they're allocated a league.

First, we ensure that when a player sends a RegistrationRequest, we input the value placement in the segments object using a key value pair like this:

  "@class": ".RegistrationRequest",
  "displayName": "",
  "password": "",
  "segments": {"league":"placement"},
  "userName": ""

This will help your Cloud Code figure out what to do with a player when they finish a game:

Events and Modules


We need to create one module.


This module will allocate the player in a division in their chosen league. This will fire after the player has been placed in their league, when they're demoted and when they're promoted.

Cloud Code for mod_DivisionPlacement:

//Load player
var currentPlayer = Spark.loadPlayer(pID);
//While loop condition
var positioned = false;
//Loop counter
var loop = 1;
//Player's league
var league = currentPlayer.getSegmentValue("league");

//While loop will check if divisions have space for this player
while(positioned === false){
   //Load the division based on the loop counter and check if it has space
    var ldrName = "ldr_Global.division.".concat(loop.toString()).concat(".league.").concat(league);
    if(Spark.getLeaderboards().getLeaderboard(ldrName) !== null){
        //Check if there's less than 100 entries (100 players)
        if(Spark.getLeaderboards().getLeaderboard(ldrName).getEntryCount() < 100){
            currentPlayer.setScriptData("division", loop);
            positioned = true;

            //If division is full, look into the next one
            loop = loop + 1;
    } else{
        //If the division doesn't exist, set it as the player's division
        currentPlayer.setScriptData("division", loop);
        positioned = true;


We'll need to create and configure three Events for this tutorial.


This Event will be used to update the global Leaderboards and division specific Leaderboards. The player will post their score, league, division, and the time posted which will help decide which Leaderboard their entry belongs to.

event_InputScore Attributes:

Name Shortcode Data Type Default Val Default Aggregation
score score Number Sum
league league String Grouped
division division Number Grouped
date date String ${format(now, "yyyy-MM")} Grouped


This event will transfer players from the 'placement' stage to a league and a division.

event_Placement Attributes:

Name Shortcode Data Type Default Val Default Aggregation
score score Number Used In Script

event_Placement Cloud Code:

//Get input Score value
var inputScore = Spark.getData().score;
//Get player ID
var pID = Spark.getPlayer().getPlayerId();

//Add score to player's placement score
var scriptScore = Spark.getPlayer().getScriptData("placementScore");
 //Check if score is valid
 if (scriptScore !== null){
     var score = scriptScore + inputScore;
     Spark.getPlayer().setScriptData("placementScore", score);
 //If not valid, create it
     var score = inputScore;
     Spark.getPlayer().setScriptData("placementScore", score);

 //Check how many placement games the player has attempted
 var attempts = Spark.getPlayer().getScriptData("placementAttempts");
 //Check if valid
 if(attempts !== null){
     //If 5 games have been played, check score and place player in the correct league
     if(attempts >= 5){
         if(score >= 3 && score <= 4){
            Spark.getPlayer().setSegmentValue("league", "silver")
         } else if(score >= 5){
            Spark.getPlayer().setSegmentValue("league", "gold")
         } else{
             Spark.getPlayer().setSegmentValue("league", "bronze")
         //Sort division
     //If player hasn't played 5, increment attempts
      Spark.getPlayer().setScriptData("placementAttempts", attempts+1);   
//If not valid, create a reference     
    Spark.getPlayer().setScriptData("placementAttempts", 1);


After every game all players will call this Event. This Event will:

event_EndGame Attributes:

Name Shortcode Data Type Default Val Default Aggregation
score score Number Used In Script

event_EndGame Cloud Code:

//Load variables
var league = Spark.getPlayer().getSegmentValue("league");
var score = Spark.getData().score;
var date = new Date;

//Check if player has been placed yet
if(league !== "placement"){

    if(Spark.getPlayer().getScriptData("division") === 0){

    //If player is placed, send a score to be sorted in Leaderboard
    var date = new Date;
    var year = date.getFullYear();
    var month = date.getMonth();
    var request = new SparkRequests.LogEventRequest();

    request.eventKey = "event_InputScore";
    request.score = score;
    request.league = Spark.getPlayer().getSegmentValue("league");
    request.division = Spark.getPlayer().getScriptData("division");
    //Creating partition value with the format YYYY-MM for monthly periods
    request.date = year.toString() + "-" + ("0" + (month+1).toString()).slice(-2);


} else{
    //If player hasn't been placed, update their placement details
    var request = new SparkRequests.LogEventRequest();

    request.eventKey = "event_Placement";
    request.score = score;




Global League Leaderboard

This Leaderboard will contain all entries for one league. For example, Bronze entries will be comparable and listed in one Leaderboard regardless of division.

Global League Leaderboard Fields:

Running Total Collector Filter type Filter Value Group
Input Score event_InputScore.score.all * Sum
Input Score event_InputScore.date.all * Partition
Input Score event_InputScore.league.all = bronze Maximum


Division Specific Leaderboard

This Leaderboard is configured to keep track of division specific entries so players can compare their record with players in their division.

Division Specific Leaderboard Fields:

Running Total Collector Filter type Filter Value Group
Input Score event_InputScore.score.all * Sum
Input Score event_InputScore.division.all * Partition
Input Score event_InputScore.league.all * parition

Note: Change the Leaderboard's reset frequency if you want to remove entries every day, week, or month to keep your divisions constantly changing.


Using GS Daily for Promotions and Demotions

At the end of the month, we want our players to be demoted and promoted based on how well they did. Once their league is changed they need to be placed in an available league.

The GS Daily script can be found under Cloud Code>System>Every Day. The script runs every day. You can use it to create schedule logic. In this example, we check if the day is the first of the month and, if it is, then we run our logic to promote the top 10 and demote the bottom 10 from every league.

GS Daily Script Cloud Code:

var today = new Date;

if(today.getDate() === 1){

    //Load league Leaderboards
    var bronzeLDR = Spark.getLeaderboards().getLeaderboard("bronze");
    var silverLDR = Spark.getLeaderboards().getLeaderboard("silver");
    var goldLDR = Spark.getLeaderboards().getLeaderboard("gold");;

    //Loads top 10 entries, forget top league because they can't promote
    var bronzeLDR_TOP = bronzeLDR.getEntries(10, 0);
    var silverLDR_TOP = silverLDR.getEntries(10, 0);

    //Loads bottom 10 entries, forget bottom league because they can't demote
    var silverLDR_BOT = silverLDRgetEntries(10, silverLDR.getEntryCount() - 10);
    var goldLDR_BOT = silverLDR.getEntries(10, goldLDR.getEntryCount() - 10);

    //Go through top entries and promote their players
        var pID = bronzeLDR_TOP.next().getUserId()
        Spark.loadPlayer(pID).setSegmentValue("league", "silver");
        var pID = silverLDR_TOP.next().getUserId()
        Spark.loadPlayer(pID).setSegmentValue("league", "gold");

    //Go through bottom entries and demote their players
        var pID = silverLDR_BOT.next().getUserId();
        Spark.loadPlayer(pID).setSegmentValue("league", "bronze");

        var pID = goldLDR_BOT.next().getUserId();
        Spark.loadPlayer(pID).setSegmentValue("league", "silver");