Prerequisites

  • Godot 4.x (GDScript)
  • A LightLeaderboard account, game, and API key
  • No plugins needed — HTTPRequest is built into Godot
TLS: Godot 4 ships with TLS support enabled by default. HTTPS requests to the API work out of the box — no extra configuration needed.

Submit a Score

Attach this script to any Node (e.g. your GameManager autoload or game scene root). Call submit_score() when the player's run ends.

leaderboard.gd GDScript
# Attach this script to any Node in your scene
extends Node

const API_URL = "https://yourapp.com/api/v1/games/my_game"
const API_KEY = "YOUR_API_KEY"

func submit_score(score: int, player_id: String, player_name: String) -> void:
    var http := HTTPRequest.new()
    add_child(http)
    http.request_completed.connect(_on_score_submitted.bind(http))

    var headers := [
        "Authorization: Bearer " + API_KEY,
        "Content-Type: application/json",
    ]
    var body := JSON.stringify({
        "score": score,
        "playerRefId": player_id,
        "playerName": player_name,
        "submissionId": str(Time.get_ticks_msec()),
    })
    http.request(API_URL + "/scores", headers, HTTPClient.METHOD_POST, body)

func _on_score_submitted(result, code, _headers, body, http: HTTPRequest) -> void:
    http.queue_free()
    if code == 200:
        var data = JSON.parse_string(body.get_string_from_utf8())
        print("Rank: ", data["rank"]) # show in UI

Fetch the Leaderboard

Add this to the same script. Call fetch_leaderboard() in your leaderboard scene's _ready() and populate your UI nodes in the callback.

leaderboard.gd (continued) GDScript
func fetch_leaderboard(limit: int = 10) -> void:
    var http := HTTPRequest.new()
    add_child(http)
    http.request_completed.connect(_on_leaderboard_received.bind(http))

    var headers := ["Authorization: Bearer " + API_KEY]
    http.request(
        API_URL + "/leaderboard?limit=" + str(limit),
        headers, HTTPClient.METHOD_GET
    )

func _on_leaderboard_received(result, code, _headers, body, http: HTTPRequest) -> void:
    http.queue_free()
    if code != 200:
        return
    var data = JSON.parse_string(body.get_string_from_utf8())
    for entry in data["entries"]:
        print("#%d  %s  %d" % [entry["rank"], entry["playerName"], entry["score"]])
        # populate your Label or RichTextLabel nodes here

Tips

  • Always call http.queue_free() in the completed callback to avoid memory leaks — every add_child(http) needs a matching cleanup.
  • Store the API key in a const at the top of an Autoload script so it's accessible everywhere without duplication.
  • Use Time.get_ticks_msec() as a quick submissionId. For stricter deduplication, generate a UUID using str(randi()) + str(randi()) or a plugin.
  • Use Godot's Label nodes inside a VBoxContainer to display leaderboard rows — set each Label's text in the _on_leaderboard_received callback.