# NativeWebSocket wraps System.Net.WebSockets so game engines get main thread events

> NativeWebSocket is a C# WebSocket client for Unity, MonoGame, Godot and plain .NET with no external dependencies, built on the runtime's own System.Net.WebSockets. Its real job is thread dispatch, since a game's WebSocket callbacks arrive on a pool thread and have to be moved onto the game loop.

**endel/NativeWebSocket** — 🔌 WebSocket client for Unity/MonoGame/Godot Mono - with no external dependencies (WebGL, Native, Android, iOS, UWP)

- Repository: https://github.com/endel/NativeWebSocket
- Stars: 1,735 · Forks: 208
- Language: C#
- License: NOASSERTION
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/endel-nativewebsocket

## No native plugin, because it uses the runtime's own WebSocket

The library's selling point is stated in the first bullet of its feature list: no external DLLs are required, because it uses the built-in `System.Net.WebSockets`. That single decision shapes everything else. A game engine project that pulls in a WebSocket library usually ends up shipping a platform specific binary for each target, and those binaries have to be maintained for every new engine version and every new platform. The other bullets are that WebGL and HTML5 support is available for Unity, that all major build targets are supported, that there is automatic main thread event dispatching through a `SynchronizationContext`, and that the API is very simple. The project is used by the Colyseus Unity SDK, which is the kind of adoption that tells you a game networking library has been tested against a real client.

## The hard part in a game engine is the thread, not the socket

Every engine integration in the documentation exists for one reason: a WebSocket library delivers callbacks on a thread pool thread, and a game engine will not let you touch its objects from there. The MonoGame integration makes this explicit. Adding the `WebSocketGameComponent` to the game installs a `SynchronizationContext`, so all WebSocket events fire on the game thread automatically. Godot needs no special integration at all, because Godot Mono has a built-in `GodotSynchronizationContext`. Unity is handled by the engine's own main thread context, and the documentation adds a WebGL specific warning that Unity pauses the game loop when the browser tab loses focus, which stops all send and receive callbacks, so `Application.runInBackground = true` has to be set in the script or Run In Background enabled in Player Settings. For a plain .NET console app with no `SynchronizationContext` at all, the library asks you to pump the queue yourself.

## Console applications pump the queue by hand

The generic .NET case is the one that shows the design most plainly, because there is no engine to do it for you. The documentation says that if your environment does not have a `SynchronizationContext`, for example a console app, you call `DispatchMessageQueue()` from your main loop to process events:

```csharp
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);
}
```

The sixteen millisecond sleep is roughly a frame budget, so the loop is a game loop in miniature. This is the same contract the engine integrations automate: a queue of pending events that someone drains at a safe moment. Reading the API this way also explains why the constructor overloads look the way they do. There are four of them, taking a URL, a URL plus a headers dictionary, a URL plus a subprotocol, and a URL plus a list of subprotocols, so the difference between a plain connection and one that negotiates a subprotocol is a constructor argument rather than a configuration object.

## Four events and two send methods

The event surface is deliberately small. `OnOpen` fires when the connection is established and takes no arguments, `OnMessage` receives a `byte[]` and covers both text and binary messages, `OnError` receives a string error message, and `OnClose` receives the close code. Messages arrive as bytes rather than as a decoded string, so the examples decode them themselves with `System.Text.Encoding.UTF8.GetString(bytes)`, which means a binary payload is not silently mangled by a text assumption. Sending is equally plain, with an awaitable `Send` for bytes and `SendText` for a string. The examples guard sends with a check on `websocket.State == WebSocketState.Open`, which is the pattern to copy if your loop keeps ticking after the socket has gone away, and the Unity example closes the socket in `OnApplicationQuit` while the Godot example closes it in `_ExitTree`.

## In Unity you must use a package, not the raw files

The installation instructions carry a warning that saves a debugging session. You are told not to copy the raw source files from the repository directly into your Unity project, because the core `WebSocket.cs` requires a build time transformation to add the WebGL conditional compilation guards. The supported routes are the Unity Package Manager, where you add a package from a Git URL, and the .unitypackage file from the Releases page. The Git URL matters, and there are two of them:

```bash
https://github.com/endel/NativeWebSocket.git#upm-2
```

The `#upm-2` branch carries the 2.x package, and if you need the previous 1.x package you use the URL with `#upm` instead, or check out the sources from the `1.x` branch. The project requires Unity 2019.1 or newer with the .NET 4.x runtime or later. The reason for the transformation is now clear: the WebGL build needs a different code path than the native builds, and that difference is applied at build time rather than with preprocessor directives in the file you would otherwise copy.

## Three package names, one assembly family

Outside Unity the install is a pair of `dotnet add package` commands, and the package names are not the repository name. MonoGame and .NET users install `Colyseus.NativeWebSocket` and `Colyseus.NativeWebSocket.MonoGame`, and Godot users install `Colyseus.NativeWebSocket`. The second package is the MonoGame specific piece, which is the one carrying the `WebSocketGameComponent` and the `SynchronizationContext` installation that makes the game thread receive the events. That separation is the reason the NuGet names differ from the GitHub repository, and it is worth remembering when you look for the source, since the repository is `endel/NativeWebSocket` while the packages ship under the Colyseus name. The repository itself holds a `NativeWebSocket.sln`, a `Directory.Build.props`, an `integrations/` directory, a `benchmarks/` directory and a `node-websocket-server/` folder used by the examples.

## The examples all talk to a local Node server

Runnable examples exist for all three engines, and they are wired to a test server that ships in the repository, which is a nice touch for anyone who wants to try the library without standing up a backend. The MonoGame example runs with `dotnet run --project examples/MonoGame/MonoGameExample.csproj`, the Godot one is opened in the Godot Editor with 4.x or later and C# support and run with Play, and the Unity one is imported via UPM with `Connection.cs` added to a GameObject. The server is started with npm:

```bash
cd node-websocket-server
npm install
npm start
```

It listens on `ws://localhost:3000`, sends periodic text and binary messages, and logs whatever the client sends, which is exactly what the examples expect. The licence is a custom one that GitHub cannot classify, so the LICENSE file in the repository root is the document to read if you intend to ship it inside a game, and the last push to the master branch was on 2026-08-07, with the 2.0.7 release on the same day.

## Conclusion

Adopt NativeWebSocket if you need a WebSocket client inside Unity, MonoGame or Godot and you do not want a third party native plugin in your build, because the library uses the runtime's own System.Net.WebSockets and adds only the thread dispatch your engine needs. Do not adopt it if you need features beyond a plain client, since the documented surface is connect, send, close and four events. Verify first which Unity package URL you use, because the 2.x package lives on the `upm-2` branch while the previous 1.x package is on `upm`, and note that in Unity the raw source files cannot be copied in directly because the core file needs a build time transformation.

## FAQ

### Does NativeWebSocket require any external DLLs?

No. The library uses the built-in `System.Net.WebSockets` from the .NET runtime, so no external native plugin has to be shipped with the game.

### How do I install NativeWebSocket in Unity?

Use the Unity Package Manager and add a package from a Git URL, using `https://github.com/endel/NativeWebSocket.git#upm-2` for the 2.x package, or import `NativeWebSocket.unitypackage` from the Releases page. The documentation warns against copying the raw source files, because the core file needs a build time transformation for the WebGL guards.

### Which NuGet package do I install for MonoGame or Godot?

MonoGame and .NET projects install `Colyseus.NativeWebSocket` and `Colyseus.NativeWebSocket.MonoGame`, while Godot installs `Colyseus.NativeWebSocket`. The MonoGame package carries the game component that installs the synchronization context.

### How are WebSocket events delivered on the game thread?

In MonoGame you add the `WebSocketGameComponent` to the game, which installs a `SynchronizationContext` so events fire on the game thread. Godot Mono has a built-in `GodotSynchronizationContext` and needs no extra work, and in plain .NET you call `DispatchMessageQueue()` from your main loop.

### What happens to a Unity WebSocket connection when the browser tab loses focus?

Unity pauses the game loop when the tab loses focus, which stops all WebSocket send and receive callbacks. The documentation says to set `Application.runInBackground = true` in the script or enable Run In Background in Player Settings to keep the connection active in the background.

## Sources

- [endel/NativeWebSocket on GitHub](https://github.com/endel/NativeWebSocket)
- [Issues](https://github.com/endel/NativeWebSocket/issues)
- [README](https://github.com/endel/NativeWebSocket/blob/master/README.md)
- [Releases](https://github.com/endel/NativeWebSocket/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/endel-nativewebsocket
