Skip to content

Magithar/socketio-unity

Repository files navigation

Socket.IO Unity Client

socketio-unity

The open-source real-time backbone for Unity multiplayer. Full Socket.IO v4 — namespaces, binary, ACKs, reconnect with backoff — verified in the browser, MIT-licensed, zero paid dependencies. Use it as your backend & matchmaking layer — standalone, or alongside Mirror / Netcode for in-scene sync.

CI Release Unity 2020.1+ WebGL Verified Mirror Compatible License: MIT


Where it fits

socketio-unity is a backend/transport client, not a netcode engine. It's ideal for:

  • Lobbies, matchmaking, and server-authoritative events over your own Socket.IO backend
  • WebGL browser multiplayer, where most Unity WebSocket options break
  • A signaling + backend layer for Mirror or Netcode — Socket.IO handles matchmaking and backend events; Mirror/Netcode handle in-scene sync. See the Mirror Integration sample.

Why socketio-unity?

Most Unity Socket.IO clients are closed-source, incomplete, or platform-locked. This is a clean-room, open-source alternative built from the public protocol spec.

socketio-unity Paid Asset Store client Roll your own (NativeWebSocket) Managed BaaS (Photon / Nakama / PlayFab)
License / cost MIT, free, auditable Paid, usually closed-source Free (your engineering time) Free tier → CCU/MAU pricing
Socket.IO v4 protocol Full (namespaces, binary, ACK timeouts) Partial / outdated You implement & maintain it N/A — their proprietary protocol
WebGL Verifiedlive browser demo Often broken You debug the jslib bridge Varies
Backend ownership Any Node/Socket.IO server you control Any Any Vendor-hosted, lock-in
Reconnect / host migration Built-in (backoff + jitter, session identity) Basic / hardcoded Build it yourself Managed
Works with Mirror / Netcode Yes — as the signaling/backend layer Rarely Maybe Overlaps / replaces them
Tested 76 tests in CI every commit Rare Your call Vendor's

You own the backend, you own the code, and it works in the browser. socketio-unity is the piece that talks to your Socket.IO server — not a netcode engine, and not a hosted service you rent.


Get Started Getting Started · Quick Start · Installation · Dependencies
Demo Live Demo · Videos
Learn API Guide · Architecture · API Stability · Flows · Permissions & Trust · Config Variables
Samples Basic Chat · PlayerSync · Lobby · LiveDemo · Mirror Integration
Platform Platforms · WebGL · Production Readiness
Tools Diagnostics Overlay · Profiler · Packet Tracing · Testing
Project Changelog · Migrations · Security · Contributing · License

Quick Start

1. Install via Unity Package Manager (Window > Package Manager+Add package from git URL):

https://github.com/Magithar/socketio-unity.git?path=/package

2. Connect and send events:

var socket = SocketIOManager.Instance.Socket;

socket.OnConnected += () => Debug.Log("Connected!");

socket.On("chat", msg => Debug.Log("Server: " + msg));

socket.Connect("ws://localhost:3002");
socket.Emit("chat", "Hello from Unity!");

3. Run the test server:

cd TestServer~ && npm install && npm run start:basicchat

Open the Basic Chat sample and press Play. → Full guide


Demo

Play Live Demo in Browser — WebGL build, no install required.

The demo server spins down when idle. First load may take ~40 seconds to connect — this is expected.

Sample Video
Basic Chat Watch on YouTube
Player Sync — WebGL Multiplayer Watch on YouTube

Installation

Option 1: Unity Package Manager (Recommended)

  1. Open Unity's Package Manager (Window > Package Manager)
  2. Click +Add package from git URL
  3. Enter: https://github.com/Magithar/socketio-unity.git?path=/package

Option 2: Manual

Download or clone this repository and copy the package/ subdirectory into your project's Packages/ directory (or add via Add package from disk → select package/package.json).

Dependencies

Package Source Purpose
Newtonsoft.Json com.unity.nuget.newtonsoft-json JSON serialization (built into Unity 2020.1+)
Mirror (optional) MirrorNetworking/Mirror Required only for the Mirror Integration sample

Mirror is not required for the core package or any other sample. Install it only if you intend to use the Mirror Integration sample — via Package Manager git URL or the .unitypackage from the Mirror releases page.

WebSocket transport is built-in — a modified WebSocket.cs derived from NativeWebSocket is embedded directly in the package. Do not install NativeWebSocket separately; doing so will cause duplicate class conflicts. See NOTICE.md.


Usage

Scene Setup

  1. Create an empty GameObject and attach SocketIOManager
  2. The singleton persists across scenes via DontDestroyOnLoad

Basic Connection

var socket = SocketIOManager.Instance.Socket;

socket.OnConnected += () => Debug.Log("Connected");
socket.On("chat", data => Debug.Log(data));
socket.Emit("chat", "Hello from Unity!");

Connection State

// Read current state
if (socket.State == ConnectionState.Connected)
    socket.Emit("status", "online");

// React to transitions
socket.OnStateChanged += (ConnectionState state) =>
    Debug.Log($"State → {state}");
State Meaning
Disconnected Not connected
Connecting Handshake in progress
Connected Live and operational
Reconnecting Auto-reconnect active

Error Handling

socket.OnError += (SocketError err) =>
{
    switch (err.Type)
    {
        case ErrorType.Transport:  // Network failure
        case ErrorType.Auth:       // Authentication rejected
        case ErrorType.Timeout:    // Server not responding
        case ErrorType.Protocol:   // Malformed packet
            Debug.LogError($"{err.Type}: {err.Message}");
            break;
    }
};

Namespaces

// Public namespace
var publicNs = socket.Of("/public");
publicNs.OnConnected += () => Debug.Log("/public connected");

// Authenticated namespace
var admin = socket.Of("/admin", new { token = "test-secret" });
admin.OnConnected += () => admin.Emit("ping", null, res => Debug.Log("ACK: " + res));

Namespaces are multiplexed over a single WebSocket and automatically reconnected after disconnects.

Binary Events

// Receive
socket.On("file", (byte[] data) => Debug.Log($"Received {data.Length} bytes"));

// Send with ACK
byte[] payload = File.ReadAllBytes("data.bin");
socket.Emit("upload", payload, response => Debug.Log($"Response: {response}"));

ACK Callbacks

// With custom timeout (default 5000ms)
socket.Emit("slowOp", data, response =>
{
    if (response == null) Debug.LogWarning("ACK timed out");
    else Debug.Log("Response: " + response);
}, timeoutMs: 10000);

Event Cleanup

void OnDestroy()
{
    socket?.Off("chat", chatHandler);
    socket?.Off("file", fileHandler);
}

Disconnect vs Shutdown

Scenario Method
User logs out, may return Disconnect()
Switching servers Disconnect() then Connect(newUrl)
Application quitting Shutdown()

Reconnect Configuration

socket.ReconnectConfig = new ReconnectConfig
{
    initialDelay     = 1f,
    multiplier       = 2f,
    maxDelay         = 30f,
    maxAttempts      = -1,      // unlimited
    jitterPercent    = 0.1f,    // prevents thundering herd
    connectTimeoutMs = 10000,   // abort Connect() with OnError(Timeout) if no OPEN in 10s (0 = off)
};

Presets: ReconnectConfig.Default(), .Aggressive(), .Conservative(). Full details: RECONNECT_BEHAVIOR.md

Thread Safety

All callbacks (OnConnected, OnDisconnected, OnError, On() handlers, ACK callbacks) execute on Unity's main thread via UnityMainThreadDispatcher.

RTT & Throughput

float rtt = socket.PingRttMs;
float sent = SocketIOThroughputTracker.SentBytesPerSec;
float recv = SocketIOThroughputTracker.ReceivedBytesPerSec;

Samples

Basic Chat

Production-ready "Hello World" — connection lifecycle, event handling, reconnection, cleanup.

var socket = SocketIOManager.Instance.Socket;
socket.OnConnected += OnConnected;
socket.On("chat", OnChatMessage);
socket.Connect("ws://localhost:3002");

Video · Full docs · Import via Package Manager → Samples → "Basic Chat"

PlayerSync

Real-time multiplayer synchronization — position sync at 20Hz, player join/leave, network interpolation, RTT display.

rootSocket = new SocketIOClient(TransportFactoryHelper.CreateDefault());
rootSocket.Connect("ws://localhost:3003");
var ns = rootSocket.Of("/playersync");
ns.On("existing_players", (string json) => { /* spawn remote players */ });
ns.Emit("player_move", JsonConvert.SerializeObject(movePacket));

Video · Full docs · Import via Package Manager → Samples → "Player Sync"

Lobby

Multiplayer lobby with host migration, session identity, reconnect grace window, and three-layer architecture (transport → state store → UI).

npm run start:lobby   # http://localhost:3001

Features: room creation, join-by-code, persistent identity across reconnects, session token auth, 10-second grace window, automatic host promotion.

Full docs · Import via Package Manager → Samples → "Lobby"

LiveDemo

Combines Lobby and PlayerSync into a single scene — lobby room creation flows into real-time player movement via GameOrchestrator layer toggling.

# Single-process (recommended for deployment)
npm run start:livedemo     # :3000 — /lobby + /playersync

# Or split servers for development
npm run start:lobby        # Terminal 1 — :3001
npm run start:playersync   # Terminal 2 — :3003

Full docs · Import via Package Manager → Samples → "Live Demo"

Mirror Integration

Hybrid architecture — Socket.IO handles matchmaking and backend events, Mirror handles in-scene transform sync. Supports three modes via an inspector dropdown: PeerToPeer (LAN/local), DedicatedKCP (native clients via Edgegap), DedicatedWebSocket (WebGL clients).

npm run start:mirror   # Port 3002 — lobby + /game namespace

Requires Mirror and the Lobby sample. Standalone build target recommended.

The dedicated server binary is in a companion repo: socketio-unity-mirror-server — Linux headless Unity build deployed to Edgegap, with CI/CD via GitHub Actions.

Sample docs · Architecture guide · Dedicated server repo · Import via Package Manager → Samples → "Mirror Integration"


Architecture

graph TD
    Server["Socket.IO Server"]

    subgraph Transport ["ITransport"]
        WS["WebSocketTransport<br/>Standalone / Editor"]
        WebGL["WebGLWebSocketTransport<br/>Browser JS bridge"]
    end

    subgraph Engine ["EngineIOClient"]
        Handshake["Handshake"]
        Heartbeat["HeartbeatController"]
        RTT["PingRttTracker"]
    end

    subgraph SocketIO ["SocketIOClient"]
        NSManager["NamespaceManager"]
        NS["NamespaceSocket"]
        Reconnect["ReconnectController"]
        Binary["BinaryPacketAssembler"]
    end

    Manager["SocketIOManager<br/>Unity singleton"]

    Server -- "WebSocket frames" --> Transport
    Transport --> Engine
    Engine --> SocketIO
    SocketIO --> Manager
Loading

Key principles: single WebSocket connection, namespace multiplexing, tick-driven (no background threads), IDisposable resource cleanup, Off() for leak prevention.

Full architecture docs: ARCHITECTURE.md


Supported Platforms

Platform Status
Unity Editor Supported
Windows / macOS / Linux Supported
WebGL Verified
Android / iOS Verified
Server Version Supported
Socket.IO v4.x Yes
Socket.IO v3.x / v2.x No
Engine.IO long-polling No (intentional)

Minimum Unity version: 2020.1 (set in package.json; required by the built-in Newtonsoft.Json dependency). Profiler Counters require 2020.2+.

Production Readiness

The public API is stable and frozen for v1.x. 76 automated tests (EditMode + PlayMode) run in CI on Unity 2022.3 LTS every commit — covering 22 protocol edge cases, connection-state, lobby-state, reconnect, WebGL routing, and regression suites.

Zero GC allocations in hot paths, main-thread safe, domain reload safe, configurable reconnect, IDisposable resource management. WebGL and mobile verified.

WebGL

WebGL support is production-verified. The SocketIOWebGL.jslib JavaScript bridge handles WebSocket communication in browser builds. Root and custom namespaces, binary data, auth, and reconnection all work in WebGL.

Force-refresh (Cmd+Shift+R) or use Incognito when iterating on WebGL builds to avoid cached JS/WASM issues.


Diagnostics Overlay

SocketIOManager.Instance.ShowDiagnostics = true;

Shows connection state (color-coded), RTT, active namespaces, pending ACKs, and a live event log. Throughput display requires the SOCKETIO_PROFILER_COUNTERS define.

Unity Profiler Integration

Add SOCKETIO_PROFILER to Player Settings → Scripting Define Symbols.

Marker Description
SocketIO.EngineIO.Parse Engine.IO packet parsing
SocketIO.Event.Dispatch Event handler dispatch
SocketIO.Binary.Assemble Binary frame assembly
SocketIO.Ack.Resolve ACK resolution
SocketIO.Reconnect.Tick Reconnection tick

Zero cost when define is off (~20-40ns per scope when on, 0 GC).

Profiler Counters

Add SOCKETIO_PROFILER_COUNTERS to Scripting Define Symbols (Unity 2020.2+).

Counters: SocketIO.Bytes Sent, SocketIO.Bytes Received, SocketIO.Packets/sec, SocketIO.Active Namespaces, SocketIO.Pending ACKs.

Packet Tracing

TraceConfig.Level = TraceLevel.Protocol; // None, Errors, Protocol, Verbose

Custom output via ITraceSink:

SocketIOTrace.SetSink(new MyTraceSink());

Development & Testing

Test Servers

cd TestServer~ && npm install

npm run start:basicchat    # Port 3002
npm start                  # Port 3000 (binary/auth)
npm run start:playersync   # Port 3003
npm run start:lobby        # Port 3001
npm run start:livedemo     # Port 3000 (combined lobby + playersync)
npm run start:mirror       # Port 3002 (lobby + /game namespace for Mirror integration)

Test Suite

Test Type Covers In CI
ProtocolParserTests.cs EditMode NUnit Protocol parsing edge cases (22 cases)
StressTests.cs EditMode NUnit 1K events, 10MB binary, 100 ACKs, 50 reconnects
ConnectionStateTests.cs PlayMode NUnit State transitions, OnStateChanged, namespace reconnect
LobbyStateIntegrationTests.cs PlayMode NUnit State invariants, namespace timing
BugRegressionTests.cs PlayMode NUnit Binary assembler, ACK overflow, JSON degradation
ReconnectConfigTests.cs PlayMode NUnit Defensive copy, factory presets, connect timeout default
WebGLBridgeRoutingTests.cs PlayMode NUnit WebGL text-message socket-id routing (colon-safe)
ProtocolEdgeCaseTests.cs Editor menu item Same parser cases, manual run (superseded by ProtocolParserTests)

CI

GitHub Actions with game-ci/unity-test-runner on every push/PR to main. Runs the full EditMode + PlayMode suite (testMode: all, 76 tests) against Unity 2022.3 LTS. Requires UNITY_LICENSE, UNITY_EMAIL, UNITY_PASSWORD secrets.


Contributing

Contributions welcome with one hard rule:

Clean-room only. Do not copy or port code from the official Socket.IO JS client, any paid Unity asset, or any other existing implementation. All contributions must be original.

Open an issue first for significant changes. Include Unity version, platform, and reproduction steps in bug reports.

Full guidelines: CONTRIBUTING.md

License

MIT — free for commercial and non-commercial use.

About

Socket.IO v4 client for Unity (Standalone & WebGL), implemented from protocol specifications with a Unity-friendly API.

Topics

Resources

License

Contributing

Security policy

Stars

16 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors