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.
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
dotnet add package Colyseus.NativeWebSocket
dotnet add package Colyseus.NativeWebSocket.MonoGamedotnet add package Colyseus.NativeWebSocketusing 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.
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 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();
}
}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);
}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 startThe server listens on ws://localhost:3000, sends periodic text and binary
messages, and logs anything received from the client.
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)| Event | Signature | Description |
|---|---|---|
OnOpen |
() |
Connection established |
OnMessage |
(byte[] data) |
Message received (text or binary) |
OnError |
(string errorMsg) |
Error occurred |
OnClose |
(WebSocketCloseCode code) |
Connection closed |
| 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) |
| Property | Type | Description |
|---|---|---|
State |
WebSocketState |
Connecting, Open, Closing, or Closed |
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.
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()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).
// 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.
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 must now include these methods.
In 1.x, you could copy NativeWebSocket/Assets/WebSocket/WebSocket.cs into your Unity project. In 2.x, the core source lives in src/NativeWebSocket/ and requires a build-time transformation to add WebGL conditional compilation guards. Use UPM or the .unitypackage instead of copying raw files.
| What changed | Action required |
|---|---|
MainThreadUtil / WaitForUpdate / WaitForBackgroundThread removed |
Delete any code using these classes |
| Automatic event dispatching | Remove DispatchMessageQueue() from Update() (Unity/Godot/MonoGame) |
Custom IWebSocket implementations |
Add Connect(), Close(), Send(), SendText() methods |
| Manual file copy installs | Switch to UPM or .unitypackage |
Big thanks to Jiri Hybek. This implementation is based on his work.
Apache 2.0
