Quick answer: Add the Multiplayer plugin to your project, connect to a signaling server, have one player create a room (host) and others join it (peers). The host runs the authoritative game simulation and syncs object positions to peers. Use the Multiplayer object’s built-in sync system for object state, handle latency with interpolation, and implement disconnect/host migration logic for robustness.

Adding multiplayer to a Construct 3 game is one of the most rewarding — and most challenging — features you can build. Construct 3’s built-in Multiplayer plugin uses WebRTC for peer-to-peer connections, which means players connect directly to each other without needing a game server. This keeps hosting costs near zero, but it also means you need to understand how peer-to-peer networking works and how to keep game state consistent across all connected players.

Understanding the Architecture

Construct 3’s multiplayer model is host-authoritative peer-to-peer. One player is the host and runs the real game simulation. All other players are peers who send their inputs to the host and receive game state updates back. The signaling server is only used for the initial connection handshake — once players are connected, all game data flows directly between them via WebRTC data channels.

This architecture means:

The host is always right. If there is a conflict between what the host sees and what a peer sees, the host’s version wins. Peers display an interpolated, slightly delayed view of the game.

The host bears the bandwidth cost. Every peer sends input to the host, and the host sends state updates to every peer. With 4 players, the host handles 3 incoming and 3 outgoing connections.

Latency is unavoidable. Peers see the game state as it was a few milliseconds (or more) ago. Your game design needs to accommodate this.

Setting Up the Signaling Connection

Add the Multiplayer object to your project (Insert New Object > Multiplayer). You do not place it on the layout — it is a global plugin. The first step is connecting to a signaling server, which brokers the initial connection between players.

// Connect to the signaling server
// On Start of Layout (lobby layout)

System: On start of layoutMultiplayer: Connect to signaling server
      "wss://multiplayer.construct.net/signalling"

// Handle connection result
Multiplayer: On connected to signaling serverMultiplayer: Log in with PlayerNameInput.Text

Multiplayer: On logged inStatusText: Set text to
      "Logged in as: " & Multiplayer.MyAlias

Multiplayer: On signaling errorStatusText: Set text to
      "Connection failed: " & Multiplayer.ErrorMessage

After logging in, you need room management. The host creates a room and peers join it:

// Host creates a room
Button_Host: On clickedMultiplayer: Create room
      RoomNameInput.Text max peers 4

// Peer joins a room
Button_Join: On clickedMultiplayer: Join room
      RoomNameInput.Text

// Room events
Multiplayer: On room createdStatusText: Set text to "Room created. Waiting for players..."

Multiplayer: On joined roomStatusText: Set text to
      "Joined room. Host: " & Multiplayer.HostAlias

Multiplayer: On peer connectedStatusText: Set text to
      Multiplayer.PeerAlias & " joined the game"

Syncing Game Objects

Once players are in a room and you transition to the game layout, you need to sync game objects. The host creates authoritative instances and associates them with peers. Each peer only controls their own input — the host processes everything.

// On start of game layout (HOST ONLY)
Multiplayer: Is host
System: On start of layout
    // Create a player object for each connected peerSystem: Create object Player at (100, 300)Player: Set instance variable PeerID to
      Multiplayer.MyIDMultiplayer: Sync object Player

// Also create a player for each peer
Multiplayer: Is host
Multiplayer: For each peerSystem: Create object Player at
      (100 + loopindex * 80, 300)Player: Set PeerID to
      Multiplayer.PeerIDMultiplayer: Sync object Player

The sync system automatically replicates the object’s position, angle, and size to all peers. For custom data like health, score, or animation state, you need to send that data explicitly:

// Sync custom data from host to peers
// Send reliable messages for important state changes

System: Every 0.1 seconds
Multiplayer: Is hostMultiplayer: Send message
      tag "score"
      to all peers
      message Player.Score
      mode reliable ordered

// On the peer side, receive and apply
Multiplayer: On message "score"ScoreText: Set text to
      "Score: " & Multiplayer.Message

Handling Input and Latency

Peers send their input to the host rather than directly moving their character. The host processes the input and the result syncs back to all peers. This prevents cheating and keeps the game state consistent.

// Peer sends input to host
Multiplayer: Is NOT host
System: Every tickMultiplayer: Send message
      tag "input"
      to host
      message
        Keyboard.IsKeyDown("ArrowLeft") & "," &
        Keyboard.IsKeyDown("ArrowRight") & "," &
        Keyboard.IsKeyDown("ArrowUp")
      mode unreliable

// Host receives and processes peer input
Multiplayer: Is host
Multiplayer: On message "input"
    // Parse the input stringPlayer: Pick by comparison
      Player.PeerID = Multiplayer.PeerID
    // Apply movement based on received inputPlayer: Simulate Platform pressing
      Left if tokenat(Multiplayer.Message, 0, ",") = "1"Player: Simulate Platform pressing
      Right if tokenat(Multiplayer.Message, 1, ",") = "1"Player: Simulate Platform pressing
      Jump if tokenat(Multiplayer.Message, 2, ",") = "1"

Input messages use unreliable mode because they are sent every tick. If one is lost, the next one arrives immediately. Using reliable mode for high-frequency messages creates congestion and increases latency.

The Multiplayer plugin includes built-in client-side interpolation. When enabled, peers see smooth movement for remote players even when updates arrive at irregular intervals. Enable it in the Multiplayer object properties or via events:

// Enable interpolation for smooth remote movement
System: On start of layoutMultiplayer: Set interpolation to Enabled

// Interpolation adds a small delay (typically 80-120ms)
// so the client always has two data points to interpolate between.
// This trades a tiny bit of latency for much smoother visuals.

Host Migration and Disconnection

In peer-to-peer games, the host leaving is catastrophic if not handled. You need to detect disconnections and either migrate the host role or end the session gracefully.

// Handle peer disconnection (on host)
Multiplayer: Is host
Multiplayer: On peer disconnected
    // Remove their player objectPlayer: Pick by comparison
      Player.PeerID = Multiplayer.PeerID
    → Player: DestroyMultiplayer: Send message
      tag "player-left"
      to all peers
      message Multiplayer.PeerAlias
      mode reliable ordered

// Handle host disconnection (on peer)
Multiplayer: On host disconnectedStatusText: Set text to
      "Host disconnected. Returning to lobby."System: Wait 2.0 seconds
    → System: Go to layout "Lobby"

For true host migration — where another peer automatically becomes the new host — you need to implement it manually. The Multiplayer plugin does not handle this automatically. The typical approach is to have peers maintain enough game state locally that one can take over the host role:

// Basic host migration strategy
// 1. All peers keep a local copy of critical game state
// 2. On host disconnect, the peer with the lowest ID becomes new host
// 3. New host creates a new room and existing peers rejoin

Multiplayer: On host disconnected
    // Check if we should become the new host
    // (lowest peer ID among remaining players)System: Set ShouldHost to
      true // simplified - compare peer IDs in production

System: ShouldHost = true
    → Multiplayer: Create room
      OriginalRoomName & "-migrated" max peers 4
    // Restore game state from local copy
    // Other peers join the new room name

Performance Tips for Multiplayer

Reduce sync frequency for non-critical objects. Not everything needs to sync every tick. Slowly moving objects or UI elements can sync every 5-10 ticks. Use the Multiplayer object’s bandwidth settings to control update rates.

Use unreliable mode for frequent updates. Position, rotation, and input data should use unreliable mode. Reserve reliable ordered mode for game events like scoring, player death, or chat messages.

Minimize the data you send. Instead of syncing entire object states, send only what changed. Use compact message formats — send a single string with comma-separated values rather than multiple separate messages.

Test with simulated latency. Use your browser’s network throttling tools to simulate high-latency connections during development. A game that feels good at 20ms latency can become unplayable at 150ms if you have not accounted for it.

Related Issues

If the signaling server connection fails, see Fix: Construct 3 Multiplayer Signaling Connection Failed. For AJAX and network-related errors, check Fix: Construct 3 AJAX Request CORS Error. If your game runs well in single player but has low FPS in multiplayer, see Fix: Construct 3 Performance Low FPS Lag. And if save/load breaks after adding multiplayer state, see Fix: Construct 3 Save/Load System Not Restoring State.

Start with two players. Get that working perfectly before adding more.