Guide

Godot addon

A pure-GDScript client for the Leaderboard API. No GDExtension build step, no dependencies — just copy a folder and enable the plugin.

The addon targets Godot 4.3+. It registers a global Leaderboard autoload whose methods are coroutines you call with await.

Install

1

Copy the addon folder

Copy godot/addons/leaderboard/ from the repository into your project's res://addons/ directory.

2

Enable the plugin

Open Project > Project Settings > Plugins and enable Leaderboard. This registers the Leaderboard autoload.

3

Add your credentials

In Project Settings > General > Leaderboard, set Base Url and Api Key.

project layout
your-game/
└── addons/
    └── leaderboard/
        ├── plugin.cfg
        ├── plugin.gd
        ├── leaderboard_client.gd
        └── icon.svg

Configuration

Enabling the plugin adds two project settings. They live under the leaderboard/ section and are read when the autoload is ready.

Base Url

The API origin, for example https://your-app.vercel.app. Defaults to http://localhost:3000.

Api Key

The key created by npm run admin game:create.

project.godot
; project.godot
[leaderboard]

base_url="https://your-app.vercel.app"
api_key="lgb_your_game_key"

You can also set them from code, which overrides the settings:

menu.gd
func _ready() -> void:
    # Optional: override the values from Project Settings at runtime.
    Leaderboard.configure(
        "https://your-app.vercel.app",
        "lgb_your_game_key"
    )

Your first request

Call any method with await. The result is a Dictionary you check with .ok.

game.gd
extends Node

func _ready() -> void:
    var res := await Leaderboard.submit_score(
        "classic",          # leaderboard slug
        "player-123",       # player id
        9120.0,             # score
        "Ada"               # player name (optional)
    )

    if res.ok:
        print("Rank #", res.data.entry.rank)
    else:
        push_warning("Submit failed: ", res.error)

Method reference

MethodDescription
list_leaderboards()List the game's leaderboards.
create_leaderboard(slug, name, sort_order := "desc")Create a board. sort_order is "desc" or "asc".
submit_score(board_slug, player_id, score, player_name := "", metadata := null)Submit a score and get the player's best entry and rank.
get_scores(board_slug, limit := 10, offset := 0, unique_per_player := true)Fetch the top entries.
get_player_rank(board_slug, player_id)Fetch one player's best entry and rank.
configure(url, key)Override the URL and key from Project Settings.

List leaderboards

var res := await Leaderboard.list_leaderboards()
if res.ok:
    for board in res.data.leaderboards:
        print(board.slug, " - ", board.name)

Create a leaderboard

var res := await Leaderboard.create_leaderboard(
    "classic", "Classic Mode", "desc"
)
if not res.ok:
    # A duplicate slug returns 400; ignore if that is expected.
    print(res.error)

Submit a score with metadata

var res := await Leaderboard.submit_score(
    "classic",
    "player-123",
    9120.0,
    "Ada",
    { "level": 3, "character": "mage" }
)

Read the top scores

var res := await Leaderboard.get_scores("classic", 10, 0, true)
if res.ok:
    for entry in res.data.scores:
        print("#%d  %s  %s" % [
            entry.rank,
            entry.playerName,
            entry.score,
        ])

Check a player's rank

var res := await Leaderboard.get_player_rank("classic", "player-123")
if res.ok and res.data.ranked:
    print("Rank ", res.data.entry.rank, " of ", res.data.totalPlayers)
else:
    print("Not on the board yet")

Result shape

Every method returns the same structure, so error handling is uniform.

result dictionary
{
    "ok":     bool,        # true for 2xx responses
    "status": int,         # HTTP status code (0 on network failure)
    "data":   Dictionary,  # parsed JSON response body
    "error":  String,      # error message when ok is false
    "action": String,      # name of the call that produced the result
}

Signal-based usage

Prefer signals to await? Connect to the response signal and the addon emits an event for every call.

game.gd
func _ready() -> void:
    Leaderboard.response.connect(_on_response)
    Leaderboard.get_scores("classic")

func _on_response(action: String, ok: bool, status: int, data: Dictionary) -> void:
    if action == "get_scores" and ok:
        for entry in data.scores:
            print(entry.playerName, ": ", entry.score)

HTML5 / web exports

The API sends permissive CORS headers, so the addon also works in HTML5 exports. Native desktop and mobile exports are unaffected.

Demo project

The godot/ folder in the repository is a runnable demo. Start the API with npm run dev, add a game key to Project Settings, then run the project (F5) to create a board, submit scores, print the top five, and look up a rank.

API key safety

For more control, see the REST API guide to call the service from a trusted server instead.

Under the hood

The addon uses a fresh HTTPRequest per call, so concurrent submissions never collide, and sends the key as an Authorization: Bearer header.