NativeWebSocket
🔌 WebSocket client for Unity/MonoGame/Godot Mono - with no external dependencies (WebGL, Native, Android, iOS, UWP)
Install / Use
/learn @endel/NativeWebSocketREADME
A simple, dependency-free WebSocket client library for Unity, MonoGame, Godot, and any .NET project.
- No external DLL's required (uses built-in
System.Net.WebSockets) - WebGL/HTML5 support (Unity)
- Supports all major build targets
- Automatic main-thread event dispatching via
SynchronizationContext - Very simple API
Used in Colyseus Unity SDK.
Installation
Unity
Requires Unity 2019.1+ with .NET 4.x+ Runtime
Note: Do not copy the raw source files from this repository directly into your Unity project. The core
WebSocket.csrequires a build-time transformation to add WebGL conditional compilation guards. Use one of the install methods below instead.
Via UPM (Unity Package Manager):
- Open Unity
- Open Package Manager Window
- Click Add Package From Git URL
- Enter URL:
https://github.com/endel/NativeWebSocket.git#upm-2
If you need the previous 1.x package instead, use https://github.com/endel/NativeWebSocket.git#upm in UPM, or check out the repository sources from the 1.x branch.
Via .unitypackage:
- Download
NativeWebSocket.unitypackagefrom the Releases page - In Unity, go to Assets > Import Package > Custom Package and select the downloaded file
MonoGame / .NET
dotnet add package Colyseus.NativeWebSocket
dotnet add package Colyseus.NativeWebSocket.MonoGame
Godot (C#)
dotnet add package Colyseus.NativeWebSocket
Usage
Unity
using UnityEngine;
using NativeWebSocket;
public class Connection : MonoBehaviour
{
WebSocket websocket;
async void Start()
{
Application.runInBackground = true; // Recommended for WebGL
websocket = new WebSocket("ws://localhost:3000");
websocket.OnOpen += () => Debug.Log("Connection open!");
websocket.OnError += (e) => Debug.Log("Error! " + e);
websocket.OnClose += (code) => Debug.Log("Connection closed!");
websocket.OnMessage += (bytes) =>
{
var message = System.Text.Encoding.UTF8.GetString(bytes);
Debug.Log("Received: " + message);
};
InvokeRepeating("SendWebSocketMessage", 0.0f, 0.3f);
await websocket.Connect();
}
async void SendWebSocketMessage()
{
if (websocket.State == WebSocketState.Open)
{
await websocket.Send(new byte[] { 10, 20, 30 });
await websocket.SendText("plain text message");
}
}
private async void OnApplicationQuit()
{
await websocket.Close();
}
}
WebGL note: Unity pauses the game loop when the browser tab loses focus, which
stops all WebSocket send/receive callbacks. To keep the connection active in the
background, set Application.runInBackground = true in your script or enable
Run In Background in Player Settings > Resolution and Presentation.
MonoGame
Add the WebSocketGameComponent to your game. This installs a
SynchronizationContext so all WebSocket events fire on the game thread
automatically.
using System;
using System.Text;
using Microsoft.Xna.Framework;
using NativeWebSocket;
using NativeWebSocket.MonoGame;
public class Game1 : Game
{
private WebSocket _websocket;
protected override void Initialize()
{
Components.Add(new WebSocketGameComponent(this));
base.Initialize();
}
protected override async void LoadContent()
{
_websocket = new WebSocket("ws://localhost:3000");
_websocket.OnOpen += () => Console.WriteLine("Connected!");
_websocket.OnError += (e) => Console.WriteLine("Error! " + e);
_websocket.OnClose += (code) => Console.WriteLine("Closed: " + code);
_websocket.OnMessage += (bytes) =>
{
var message = Encoding.UTF8.GetString(bytes);
Console.WriteLine("Received: (" + bytes.Length + " bytes) " + message);
};
await _websocket.Connect();
}
protected override async void OnExiting(object sender, EventArgs args)
{
if (_websocket != null)
await _websocket.Close();
base.OnExiting(sender, args);
}
}
Godot
Godot Mono has a built-in GodotSynchronizationContext, so no special
integration is needed. All WebSocket events fire on the main thread
automatically.
using System.Text;
using Godot;
using NativeWebSocket;
public partial class WebSocketExample : Node
{
private WebSocket _websocket;
public override async void _Ready()
{
_websocket = new WebSocket("ws://localhost:3000");
_websocket.OnOpen += () => GD.Print("Connected!");
_websocket.OnError += (e) => GD.Print("Error! " + e);
_websocket.OnClose += (code) => GD.Print("Closed: " + code);
_websocket.OnMessage += (bytes) =>
{
var message = Encoding.UTF8.GetString(bytes);
GD.Print("Received: (" + bytes.Length + " bytes) " + message);
};
await _websocket.Connect();
}
public override void _ExitTree()
{
_websocket?.Close();
}
}
Generic .NET (no SynchronizationContext)
If your environment doesn't have a SynchronizationContext (e.g. a console
app), call DispatchMessageQueue() from your main loop to process events:
var ws = new WebSocket("ws://localhost:3000");
ws.OnMessage += (bytes) => Console.WriteLine("Received " + bytes.Length + " bytes");
_ = ws.Connect();
while (true)
{
ws.DispatchMessageQueue();
Thread.Sleep(16);
}
Examples
Full runnable examples are in the examples/ directory:
| Engine | Path | How to run |
|--------|------|------------|
| MonoGame | examples/MonoGame/ | dotnet run --project examples/MonoGame/MonoGameExample.csproj |
| Godot | examples/Godot/ | Open in Godot Editor (4.x+ with C#), build, and press Play |
| Unity | examples/Unity/ | Import NativeWebSocket via UPM, add Connection.cs to a GameObject |
All examples connect to the included test server:
cd node-websocket-server
npm install
npm start
The server listens on ws://localhost:3000, sends periodic text and binary
messages, and logs anything received from the client.
API
Constructor
new WebSocket(string url)
new WebSocket(string url, Dictionary<string, string> headers)
new WebSocket(string url, string subprotocol)
new WebSocket(string url, List<string> subprotocols)
Events
| Event | Signature | Description |
|-------|-----------|-------------|
| OnOpen | () | Connection established |
| OnMessage | (byte[] data) | Message received (text or binary) |
| OnError | (string errorMsg) | Error occurred |
| OnClose | (WebSocketCloseCode code) | Connection closed |
Methods
| Method | Description |
|--------|-------------|
| Connect() | Connect to the server (async) |
| Close(code, reason) | Gracefully close the connection (async) |
| Send(byte[]) | Send binary data (async) |
| SendText(string) | Send text data (async) |
| CancelConnection() | Cancel a pending connection attempt |
| DispatchMessageQueue() | Manually dispatch queued events (only needed without a SynchronizationContext) |
Properties
| Property | Type | Description |
|----------|------|-------------|
| State | WebSocketState | Connecting, Open, Closing, or Closed |
Migrating from 1.x
Breaking changes
Universal .NET library
The core library no longer depends on UnityEngine. It targets netstandard2.0 and net6.0, and works across Unity, MonoGame, Godot, and any .NET project. Unity-specific code (WebGL) has been moved to separate integration files.
MainThreadUtil, WaitForUpdate, and WaitForBackgroundThread removed
These Unity-specific classes have been removed. Event dispatching is now handled automatically via SynchronizationContext. Remove any references to these classes from your code.
// 1.x — these no longer exist in 2.x
MainThreadUtil.Instance
MainThreadUtil.synchronizationContext
new WaitForUpdate()
new WaitForBackgroundThread()
Automatic event dispatching — no more Update() dispatch loop
In 1.x, you had to call DispatchMessageQueue() every frame from Update():
// 1.x — REQUIRED in Update()
void Update() {
websocket.DispatchMessageQueue();
}
In 2.x, events are automatically dispatched to the main thread via SynchronizationContext in Unity, Godot, and MonoGame (with WebSocketGameComponent). Remove the Update() dispatch call. DispatchMessageQueue() is only needed in environments without a SynchronizationContext (e.g. console apps).
Close() accepts close code and reason
// 1.x — no parameters
await websocket.Close();
// 2.x — optional close code and reason
await websocket.Close(WebSocketCloseCode code = WebSocketCloseCode.Normal, string reason = null);
Existing Close() calls without arguments still compile. However, if you implemented the IWebSocket interface directly, you must update your implementation to match the new signature.
IWebSocket interface expanded
The interface now declares methods in addition to events and state:
// 2.x interface
public interface IWebSocket {
event WebSocketOpenEventHandler OnOpen;
event WebSocketMessageEventHandler OnMessage;
event WebSocketErrorEventHandler OnError;
event WebSocketCloseEventHandler OnClose;
WebSocketState State { get; }
// New in 2.x
Task Connect();
Task Close(WebSocketCloseCode code = WebSocketCloseCode.Normal, string reason = null);
Task Send(byte[] data);
Task SendText(string message);
}
Any custom IWebSocket implementation
Related Skills
node-connect
337.7kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.3kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
337.7kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.3kCommit, push, and open a PR
