Home/Engines/Godot multiplayer

engines · Godot

Godot multiplayer

Godot's high-level MultiplayerAPI is excellent netcode, but you still have to run the server. This is the hosted part: accounts, rooms, matchmaking, shared state and relay, reachable from GDScript over plain HTTP.

Free sandbox · $19.99/mo to go live · cancel anytime

why

Two ways to use it from Godot

  • Web exports: call the JavaScript SDK through JavaScriptBridge and get WebRTC peer-to-peer with relay fallback for free.
  • Native exports: talk to the API over HTTP with HTTPRequest. Three routes are enough to play; the OpenAPI 3.1 schema documents the rest. Traffic uses the server relay in /v1/rt/sync, whose cadence the server tells you in tick_ms.
code

A complete Godot integration

extends Node

const API := "https://multiplayerapi.com/v1"
const KEY := "mp_pk_..."
var token := ""
var room_code := ""
var since := 0
var tick_ms := 1000

func _ready() -> void:
    var guest = await post("/auth/guest", {"display_name": "Player"})
    token = guest.session.access_token
    var qm = await post("/rooms/quickmatch", {"mode": "ffa", "max_players": 8})
    room_code = qm.room.code
    tick_ms = qm.tick_ms
    loop()

func loop() -> void:
    while room_code != "":
        var r = await post("/rt/sync", {
            "room": room_code, "since": since, "transport": "relay",
            "relay": [{"data": Marshalls.utf8_to_base64(JSON.stringify({"x": $Player.position.x, "y": $Player.position.y}))}],
        })
        since = r.seq
        tick_ms = r.tick_ms                      # always respect the server cadence
        for p in r.relay:
            var pos = JSON.parse_string(Marshalls.base64_to_utf8(p.data))
            update_remote(p.from, pos)
        await get_tree().create_timer(tick_ms / 1000.0).timeout

func post(path: String, body: Dictionary) -> Dictionary:
    var http := HTTPRequest.new()
    add_child(http)
    var headers := ["Content-Type: application/json", "X-Mp-Key: " + KEY]
    if token != "":
        headers.append("Authorization: Bearer " + token)
    http.request(API + path, headers, HTTPClient.METHOD_POST, JSON.stringify(body))
    var res = await http.request_completed
    http.queue_free()
    return JSON.parse_string(res[3].get_string_from_utf8())
architecture

What goes where

ChannelCallDeliveryUse it for
Directroom.send(data)peer-to-peer, best effort, zero server costpositions, aim, animation
Stateroom.set(path, value)server-validated, kept for the match, reaches late joinershealth, score, whose turn
Eventsroom.emitEvent(topic, data)ordered, guaranteed, not persistedchat, rematch, one-shots
  • Write health and score with ops in the same sync call: {"op":"set","path":"players.$me.hp","value":80}.
  • Batch profile, stats and leaderboard reads with POST /v1/batch (up to 20 calls).
Questions
How is this different from Godot's MultiplayerAPI?

Godot's MultiplayerAPI is an engine-level networking layer; you still decide where the server runs and who pays for it. Multiplayer API is a hosted service you call over HTTP and WebRTC, including accounts, matchmaking, leaderboards and validated state.

Does it support Godot 4 web exports?

Yes, and that is the best path: the JavaScript SDK gives web exports WebRTC peer-to-peer with automatic relay fallback.

Is there an official GDScript SDK?

Not yet. The HTTP API is small (three routes to play) and fully described by an OpenAPI 3.1 schema, as shown above.

Make your game online today

Free sandbox keys in one call, no account and no card. $19.99/month when you ship, for every game you make.

Free sandbox · $19.99/mo to go live · cancel anytime