Client SDK · C# · Version 0.1.0
Unity SDK
Bring players into the same conversation. Build live chat, lobbies, ready states, score updates and turn-based games with pubb events and presence.
Install with Unity Package Manager
The package targets Unity 2022.3 LTS or newer with .NET Standard 2.1 API compatibility. Native and WebGL transports are included; see platform verification status before shipping.
With Git installed, open Window → Package Manager → + → Add package from git URL and paste this version-pinned URL:
https://github.com/pubbio/sdk-unity.git#v0.1.0
You can also install the downloadable package:
- Download
io.pubb.unity-0.1.0.tgzabove. - In Unity, open Window → Package Manager.
- Choose + → Add package from tarball and select the downloaded file.
- Unity resolves Newtonsoft JSON 3.2.1 and the required Unity modules. If your scripts use an assembly definition, reference
Pubb.UnityandUnity.Newtonsoft.Json.
For local source development, choose Add package from disk and select package.json in your SDK checkout. The tarball includes runtime source, an API README, Editor tests and a chat/lobby sample. It is a downloadable UPM package; no Asset Store or OpenUPM installation is required.
Receive your first event
Create PubbQuickstart.cs, attach it to a GameObject and enter the public app key from your pubb application. Call Tick() in Update() so events reach Unity on the main thread.
using Pubb.Unity;
using UnityEngine;
public sealed class PubbQuickstart : MonoBehaviour
{
[SerializeField] private string appKey = "YOUR_PUBLIC_APP_KEY";
private PubbClient pubb;
private void OnEnable()
{
pubb = new PubbClient(new PubbOptions { AppKey = appKey });
pubb.Error += error => Debug.LogWarning(error);
pubb.StateChanged += state => Debug.Log("pubb: " + state);
pubb.Subscribe("notifications")
.Bind("pubb:subscription_succeeded", _ => Debug.Log("Ready to receive"))
.Bind("message.sent", data => Debug.Log((string)data["message"]));
pubb.Connect();
}
private void Update() => pubb?.Tick();
private void OnApplicationPause(bool paused)
{
if (paused) pubb?.Disconnect();
else pubb?.Connect();
}
private void OnDisable() { pubb?.Dispose(); pubb = null; }
}
When the Console shows Ready to receive, publish message.sent to notifications from the same application’s Live console with the payload below. The Unity Console should print the message.
{"message":"Hello Unity!"}
The example uses a public channel. Anyone with the public app key can subscribe; use authorized channels for player conversations and private game data.
Private channels and presence
Provide an authenticated endpoint in your backend. The SDK posts socket_id and channel_name; your backend checks that the player belongs to that room and returns auth, plus the unchanged signed channel_data string for presence.
using System.Collections.Generic;
using Pubb.Unity;
var client = new PubbClient(new PubbOptions {
AppKey = "YOUR_PUBLIC_APP_KEY",
Authorizer = new HttpChannelAuthorizer("https://game.example.com/auth",
() => new Dictionary<string, string> {
["Authorization"] = "Bearer " + currentSessionToken
})
});
var lobby = client.Subscribe("presence-lobby-42");
lobby.Bind("pubb:subscription_succeeded", _ => {
// Refetch the saved lobby/game state here, on initial join AND reconnect.
foreach (var member in lobby.Members)
UnityEngine.Debug.Log(member.Key);
});
lobby.Bind("pubb:member_added", member => UnityEngine.Debug.Log(member["user_id"]));
lobby.Bind("pubb:member_removed", member => UnityEngine.Debug.Log(member["user_id"]));
client.Connect();
// Retain client, call Tick in Update, and Dispose on owner teardown.
currentSessionToken comes from your game’s sign-in flow. The headers callback is evaluated for every authorization attempt, including reconnects. Keep the client in an owning component, pump it from Update and dispose it on teardown as in the quickstart.
Use your backend’s server SDK to sign subscriptions, or call the authorization HTTP endpoint from trusted server code. Derive the player’s identity from the authenticated session. The Unity SDK never needs the pubb app secret.
Presence tracks connected members. Readiness, seats, host permissions and matchmaking belong to your game’s saved state. Multiple connections for one user count as one presence member.
Try the included chat and lobby sample
- Select pubb Unity SDK in Package Manager and import Chat and lobby from Samples.
- Attach
ChatAndLobbyto an empty GameObject and set your public app key. - Follow the imported README to run
backend/server.mjswith Node.js 22+, your server credentials and two distinct demo player tokens. No npm dependencies are required. - Keep
presence-lobby-demoas the channel andhttp://localhost:3210as the backend for a local Editor run. - Enter one demo session token in each player instance. Send chat messages and toggle Ready. Both players read the same saved lobby state.
The sample includes room authorization, presence, ready controls, a score display, versioned state refresh, command deduplication and a bounded publication retry queue. Score changes must originate in trusted game logic; the sample rejects client score commands.
The demo stores state and retries in memory and binds only to loopback. For production, use persistent storage, a transactional outbox, real expiring sessions and a reachable HTTPS backend. The sample does not require you to adopt Node.js for an existing backend.
Send chat messages and game commands
Unity sends a command to your authenticated backend. The backend checks membership, validates the action, saves it and publishes the result. For example: player sends message → backend saves message → pubb delivers chat.message → clients refresh the conversation.
// Trusted backend only. Run after authenticating the player,
// checking room access and saving the message.
const response = await fetch(
`https://api.pubb.io/api/apps/${process.env.PUBB_APP_ID}/events`,
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PUBB_APP_SECRET}`,
"Content-Type": "application/json",
"Idempotency-Key": "chat-message-1042",
},
body: JSON.stringify({
channel: "presence-lobby-demo",
name: "chat.message",
data: { id: "1042", name: "Alex", text: "Ready for the next round?" },
}),
},
);
if (response.status !== 202) throw new Error("Publication was not accepted");
There is no client Publish API: pubb’s WebSocket accepts subscription commands, while publishing requires the server secret. Never put that secret in scenes, Inspector fields, PlayerPrefs or a shipped binary.
HTTP 202 means accepted for processing, not delivered. Retry the same saved event with the same idempotency key. Store message history in your database; event payloads are limited to 10 KiB of UTF-8 JSON.
Build around the next turn
| Experience | Example events | Your backend owns |
|---|---|---|
| Live chat | chat.message | Membership, moderation and saved messages |
| Lobbies and ready states | lobby.updated, match.started | Seats, invitations, host permissions and readiness |
| Cards and okey | turn.changed, hand.updated | Shuffling, dealing, legal moves and hidden hands |
| Chess and turn-based strategy | move.accepted, turn.changed | Move validation, turn order, clocks and saved board state |
| Live scores | score.updated, round.ended | Score calculation and authoritative outcomes |
Use a shared authorized room channel for the visible board and a separate private channel per player for cards, tiles or fog-of-war state. Never include every player’s hidden hand in a room-wide event.
Give commands unique IDs and state a monotonic version. Reject duplicate commands and stale state; fetch a fresh snapshot after joining or reconnecting. The SDK provides messaging and presence. Physics synchronization, transform replication, rollback and competitive FPS netcode require a separate game networking layer.
Handle disconnects and scene changes
- Use one client per owning session; call every SDK method and
Tick()on Unity’s main thread. Connectedmeans the WebSocket handshake is complete. Wait for each channel’spubb:subscription_succeededbefore expecting events.- Unexpected failures retry up to five times with exponential backoff and jitter. A healthy 30-second connection resets the retry budget. After
Failed, callConnect()to try again. - Reconnect creates a fresh socket ID, reauthorizes private/presence channels and rebuilds subscriptions. Commands are paced at most ten per second.
- Call
Disconnect()when pausing andConnect()on resume. CallDispose()before changing users or destroying the owner. - Refresh saved state after every subscription acknowledgement. Missed events are not replayed; periodic backend refresh can also recover an event missed without a detected disconnection.
Authorization or subscription failure emits pubb:subscription_error and is not retried in a tight loop. Fix the session or permission, then unsubscribe and subscribe again, or reconnect. Slow readers have bounded queues; overflow triggers connection recovery.
API reference
| API | Purpose |
|---|---|
Connect / Tick / Disconnect / Dispose | Start, pump, pause and permanently release the client |
Subscribe(name) / Unsubscribe(name) | Manage up to 100 desired channels; repeat Subscribe returns the same channel |
State / StateChanged / SocketId / Error | Observe connection state and errors |
channel.Bind / Unbind / UnbindAll | Manage callbacks receiving Newtonsoft JToken payloads |
channel.IsSubscribed / Members | Read acknowledgement state and presence members keyed by user ID |
HttpChannelAuthorizer | Authorize subscriptions using your backend and current session headers |
PubbOptions accepts AppKey, SocketUrl (default wss://ws.pubb.io/socket, without a query), Authorizer, TimeoutSeconds (default 15) and MaxReconnectAttempts (default 5). Set retries to zero to disable automatic reconnection. The package README documents extension interfaces and all lifecycle events.
Platforms and verification
Editor, desktop, Android and iOS use the native ClientWebSocket transport. WebGL uses the included browser bridge. Both handle WebSocket control-frame Ping/Pong. WebGL HTTP authorization and commands require CORS for your exact game origin, including Authorization and Content-Type headers.
Use HTTPS/WSS outside loopback development. A phone or hosted browser cannot reach your computer using its own localhost. Configure internet access and TLS trust in your Unity project, and use a separate push service for closed-app notifications. Consoles have not been evaluated.
Version 0.1.0 has automated core protocol/lifecycle tests, a real loopback WebSocket test, JavaScript bridge tests and sample-backend HTTP tests. Unity Editor compilation, IL2CPP and Android/iOS/WebGL player builds have not been verified in the development environment. Validate your target build before production use.
To enable the included Editor tests, add "testables": ["io.pubb.unity"] to your project’s Packages manifest, keeping existing entries, then use the Unity Test Runner’s EditMode tab. Confirm two-player delivery, denied access, reconnect, pause/resume and scene cleanup on each target platform.