Your game's server tells us how well a player is doing, and their standing becomes part of their place on your leaderboard and in your tournaments.
One call with one number. Your game already knows who its best players are; this is how it says so, and it is the only part of a player's standing on your leaderboard that comes from inside the game.
The number means whatever you mean by it. Points, coins, waves survived, a lap time you have turned upside down so bigger is better. Nothing here interprets it, and no game's score is ever compared with another game's: your players are ranked against each other, and that ranking is what becomes a 1 to 100 score on the board. A game that hands out millions a round and a game that counts to nine both work, and changing how you score does not break anybody's standing as long as it keeps the order.
import { Indie } from 'indie-sdk/server';
const indie = new Indie({
appId: process.env.INDIE_APP_ID,
appSecret: process.env.INDIE_APP_SECRET,
});
// Wherever your server knows the number: end of a match, end of a run.
await indie.submitScore(playerId, 12500);playerId is the player's indie.fun account id: the id of the signed-in user the browser SDK gives your game, which your server can confirm with indie.verifyToken(token). Only a player's best is kept, so reporting every round is fine, a bad run never lowers what they achieved, and a retried request never double-counts.
Only your server can report a score
A score decides a player's place on your leaderboard, which can decide whitelist places on your raise and the prizes of your tournaments. Code running in a player's browser is code the player controls, and anybody can type a score of a billion into the console. So a score is accepted only with your App Secret, which lives on your server and never in a page.
The browser SDK's indie.submitScore(score) used to send one from the page. It now sends nothing and warns in the console; games still calling it keep working, they just do not score.
A game often counts several things: experience, gold, a tournament high score. Name each one with a type and each keeps its own best for every player:
await indie.submitScore(playerId, 1250, { type: 'xp' });
await indie.submitScore(playerId, 40, { type: 'gold' });
await indie.submitScore(playerId, 98000, { type: 'tournament_highscore' });A type is a name you choose: lower case letters, digits, _ and -, at most 32 of them (XP is read as xp). A score with no type is your game's score, which is what every score was before types existed. A game can report up to 50 types. Once your server has reported a type, your leaderboard's settings offer it when you add a column.
On your game's leaderboard at indie.fun/leaderboard/your-game, as the Game score column, and in your game's tournaments. Each score type is a column you add yourself.
submitScore(playerId, score, { type? })Report a player's score. 0 to 1e15. Only their best is kept, per type. No type is your game's score.POST /api/player/scoreBody { userId, score, type? }, with X-App-Id and X-App-Secret. Refused without the secret.