← All posts

Real-Time Browser Game Netcode: WebSockets & Lag Compensation

Master real-time browser game netcode by exploring WebSockets, client-side prediction, lag compensation, and state reconciliation.

If you have ever tried to play a twitch-reaction browser game over a flaky home Wi-Fi connection only to watch your character teleport straight into a laser beam, you have met the internet's most undefeated villain: latency.

Building snappy, responsive multiplayer browser games is no mean feat. While desktop apps have decades of native optimisation tricks up their sleeves, web developers building high-speed browser games are working right inside the constraints of the browser sandbox. Yet, thanks to modern JavaScript engines, WebSockets, and WebRTC, indie web games are pulling off silky-smooth real-time multiplayer matches that would have melted a browser ten years ago.

Here is a deep dive into the netcode architecture keeping your favourite browser games buttery smooth, featuring the holy trinity of responsive multiplayer: client-side prediction, lag compensation, and state reconciliation.

Entity Definition: What is Browser Game Netcode?

Browser Game Netcode refers to the programming architecture and synchronisation protocols used to transmit player inputs, game state updates, and physics calculations between a remote server and multiple web browsers in real-time, typically leveraging lightweight TCP-based WebSockets or unreliable WebRTC data channels.

To understand why traditional web request models fail for multiplayer games, we need to look at how basic data transfer works.


[ Browser Client ] ---( WebSocket Frame )---> [ Node.js Game Server ]
       |                                              |
       |<------------ ( State Broadcast ) ------------|

The Network Reality: Why TCP and WebSockets Hate Games

When you build a standard web app, you use HTTP or standard WebSockets running over TCP. TCP guarantees that every single packet arrives safely and in the correct order. If a packet gets lost in transit, TCP hits the pause button, demands a resend, and freezes your data stream.

For a chat app, this is brilliant. For a fast-paced browser arena shooter running at 60 frames per second, a sudden 150-millisecond TCP retransmission stall means your game freezes completely.

This is why indie developers building high-frequency browser games must design custom state loops over WebSockets—or pivot to unreliable WebRTC data channels where dropping an old packet is infinitely better than waiting for a late one.


The Three Pillars of Responsive Multiplayer

If you wait for the server to confirm every single button press before moving a player's sprite on screen, your game will feel like walking through cold custard. Even with a brilliant ping of 30ms, that round-trip delay creates a sluggish, unplayable mess.

To fix this, developers rely on three core architectural patterns discussed across community subreddits, GitHub architecture repos, and technical YouTube post-mortems.

1. Client-Side Prediction (CSP)

Instead of waiting for the server, the client immediately updates its local display the moment you press an arrow key. You don't wait for permission; you predict your own movement locally.

2. Server Reconciliation

What happens when your client prediction conflicts with the authoritative server state? The server always wins. State reconciliation is the delicate art of the client accepting a correction from the server without violently snapping the player's position across the screen.

3. Lag Compensation (Rewind Time)

If a player with a 150ms ping shoots at a moving target, where is that target really from the shooter's perspective? Without lag compensation, you would have to aim miles ahead of your opponent. Servers with lag compensation temporarily roll back the hitboxes in time to check if a shot truly connected on the shooter's screen.


Architecture Comparison Table

Netcode TechniquePrimary BenefitMain DrawbackBest Used For
Lockstep / DeterministicMinimal bandwidth usageEntire game freezes if one client lagsTurn-based & RTS browser games
Server AuthoritativeCompletely stops basic cheatingHigh perceived input latency if unoptimisedMMOs & competitive arena titles
Client Prediction + ReconInstant, zero-latency local feelRequires complex maths to smooth correctionsFast platformers & action titles

Implementing Client-Side Prediction: A Code Blueprint

Here is a simplified conceptual example of how a JavaScript browser client handles local input prediction before waiting for the server response queue.


// Local player state loop running at 60fps in the browser
class PlayerEntity {
    constructor() {
        this.x = 100;
        this.y = 100;
        this.inputQueue = [];
        this.pendingInputs = [];
    }

    handleInput(input, sequenceNumber) {
        // 1. Instantly apply movement locally (Client-Side Prediction)
        this.updatePosition(input);

        // 2. Stamp the input with an incrementing sequence ID
        const timedInput = { sequenceNumber, input, timestamp: Date.now() };
        this.inputQueue.push(timedInput);
        this.pendingInputs.push(timedInput);

        // 3. Transmit payload over WebSocket to authoritative server
        webSocketConnection.send(JSON.stringify({
            type: 'PLAYER_INPUT',
            payload: timedInput
        }));
    }

    updatePosition(input) {
        if (input.keys.includes('ArrowUp')) this.y -= 5;
        if (input.keys.includes('ArrowDown')) this.y += 5;
    }
}

When the server processes this input, it returns the definitive player coordinate along with the latest processed sequenceNumber. The client then loops through its pendingInputs array, discards anything older than the server's processed ID, and smoothly interpolates any minor discrepancies—a process known as error smoothing or lerping.


Key Takeaways for Web Game Devs

  • Never trust the client: Always run authoritative physics checks on the server to prevent speed-hacks and invalid state manipulation.
  • Embrace interpolation: Never hard-snap a player entity to a new coordinate; always lerp (linear interpolate) positions over 2 to 3 frames to keep motion looking organic.
  • Minimise payload sizes: Avoid heavy JSON stringification for high-frequency game loops where possible; consider using binary ArrayBuffers or TypedArrays over WebSockets to save precious milliseconds.

Thanks for reading. Browse more from the Wobblox blog, or jump straight into all 100 free games.