Skip to content

API reference

The Unity SDK’s entire public surface is one MonoBehaviour: PhoneControllerManager. This page lists every event, method, and property on it, plus the supporting types you’ll touch.

For task-oriented walkthroughs, see Quickstart, FlowAsset, and the per-widget pages.

PhoneControllerManager

Attach to a GameObject. Reference it from your game code via [SerializeField] or FindObjectOfType<PhoneControllerManager>().

Events

All events fire on the Unity main thread. Subscribe in Awake or Start; unsubscribe in OnDestroy to avoid leaks across scene loads.

EventSignatureFires when
OnPlayerJoinAction<Player>A controller joined the session (initial join or resume).
OnPlayerLeaveAction<Player, LeaveReason>A controller left. See LeaveReason.
OnPlayerUpdateAction<Player>A connected player’s display name or color changed mid-session.
OnInputAction<Player, InputEvent>A widget emitted an event. Catch-all; prefer OnWidgetInput with flows.
OnPlayerScreenChangeAction<Player, string from, string to>A player transitioned screens within a flow.
OnPlayerScreenAcknowledgedAction<Player, string screen, long revision>Phone confirmed a screen.show was applied locally.
OnStatusChangeAction<ConnectionStatus>Connection status changed. See ConnectionStatus.
OnSessionChangeAction<string code, string joinUrl>Fires on initial connect and on every reconnect (same code or a fresh one).
OnErrorAction<string>Relay reported a system.error. The string is the human-readable message.
OnResendFailedAction<ResendFailure>Fire-and-forget RequestResend couldn’t be honored.

Connection methods

MethodNotes
Task ConnectAsync()Called automatically if autoConnect is ticked on the inspector.
Task DisconnectAsync()Cancels every pending PromptAsync / RequestAsync first, then closes the socket.
void ClearCachedSession()Forget the persisted (code, host_id). Next connect allocates a fresh code.

Sending events to phones

MethodNotes
void SendToPlayer(string playerId, string eventType, object payload = null)Fire-and-forget. Errors via OnError.
void BroadcastToAllPlayers(string eventType, object payload = null)Fire-and-forget fan-out.
Task<BroadcastResult> SendToPlayerAsync(...)ACK-tracked. Result reports Delivered / Missed / TimedOut.
Task<BroadcastResult> BroadcastToAllPlayersAsync(...)ACK-tracked fan-out.

Flow control (multi-screen sessions)

These require a FlowAsset registered on the manager. See FlowAsset.

MethodNotes
void UseFlow(Flow flow)Register a flow at runtime (alternative to the Flow Asset inspector slot).
void ShowScreen(string playerId, string screenName, object data = null)Move one player to a screen.
void ShowScreen(IEnumerable<string> playerIds, ...)Move several players.
void ShowScreenToAll(string screenName, object data = null)Move every connected player.
void UpdateScreenData(string playerId, string screenName, object patch)Shallow-merge new data into a player’s current screen.
void UpdateScreenDataForAll(string screenName, object patch)Same, fan-out.
Action OnWidgetInput(string screenName, string widgetId, Action<Player, InputEvent> handler)Scoped subscription. Returns the unsubscribe delegate.

Request/response

MethodNotes
Task<InputEvent> PromptAsync(...)One player, one screen, one widget, one response. Flow only. Typed: PromptAsync<T>. See PromptAsync.
Task<InputEvent> RequestAsync(...)Same shape, no flow required. Modal overlay. Typed: RequestAsync<T>. See RequestAsync.
void RequestResend(...)Fire-and-forget lossy-stream replay (drawing canvas).
Task<ResendResult> RequestResendAsync(...)Awaitable resend with positive ACK. See RequestResendAsync.

Properties

PropertyTypeNotes
SessionCodestringCurrent 4-character code. Empty until the first session arrives.
JoinUrlstringFull URL for QR-display.
StatusConnectionStatusCurrent connection state.
PlayersIReadOnlyList<Player>Currently connected controllers.
TemplateControllerTemplateThe bound template asset (single-screen sessions).
CapabilitiesTransportCapabilitiesStatic metadata about the active transport.
IsLanModeboolConvenience for Capabilities.RelayKind == RelayMode.Lan.
RelayCapabilitiesRelayCapabilitiesWhat the relay actually advertised in session.created. Null until first session arrives.

Supporting types

Player

Stable per-session identity for a connected phone.

FieldTypeNotes
IdstringStable identifier (p_1, p_2, …). Survives reconnect.
DisplayNamestringPlayer-chosen name.
Colorstring7-digit hex assigned by the relay’s join-counter palette.
JoinedAtDateTimeOffsetWhen the relay first accepted this player.

InputEvent

Per-widget event with typed accessors.

FieldTypeNotes
WidgetIdstringMatches the widget’s id.
EventTypestringPer-widget event name (see widget pages for the catalog).
RawJsonJObjectFull payload as Newtonsoft. Use as escape hatch.

Typed accessors:

AccessorReturns
GetVector2()(x, y) for joystick events.
GetString(string key)A string field from the payload. Returns null if absent or wrong type.
GetInt(string key)An int field.
GetBool(string key)A bool field.
GetStringArray(string key)A string array (e.g. choice_ids from multi-select).
As<T>()Deserialize the raw payload to T. Throws InvalidOperationException on null.

Per-widget conventions are summarized on each widget’s reference page (e.g. joystickGetVector2(), text_inputGetString("text")).

LeaveReason

public enum LeaveReason
{
Timeout, // Phone disconnected; reconnect grace window expired.
UserLeft, // Phone sent session.leave with reason=user_left.
HostClosed, // Host kicked / closed the session.
Kicked, // Server-side enforcement (rate limit, abuse).
}

ConnectionStatus

public enum ConnectionStatus
{
Disconnected,
Connecting,
Connected,
Reconnecting, // Transient — exponential backoff in progress.
Failed, // Reconnect-attempt budget exhausted (cloud transport only).
}

TransportCapabilities

Static metadata about the active transport, populated before connect from relayMode.

FieldTypeNotes
RelayKindRelayModeCloud or Lan.
SessionSurvivesHostRestartboolTrue on Cloud (Upstash), false on LAN (in-process state).
EnforcesRateLimitsboolTrue on Cloud, false on LAN.

RelayCapabilities

What the running relay advertised in session.created. Use this to branch on optional features.

FieldTypeNotes
StrictPayloadsboolIf true, register payload validators (see Validation).

Older relays that don’t include the field leave RelayCapabilities null.

BroadcastResult

Returned by BroadcastToAllPlayersAsync and SendToPlayerAsync.

FieldTypeNotes
DeliveredIReadOnlyList<string>Player IDs that ACKed within the timeout.
MissedIReadOnlyList<string>Player IDs the relay never delivered to.
TimedOutIReadOnlyList<string>Player IDs that didn’t ACK in time.

ResendStatus, ResendResult, ResendFailure

public enum ResendStatus { Accepted, Rejected, TimedOut }
public record ResendResult
{
public ResendStatus Status;
public int ReplayedCount; // Accepted: how many events the phone is replaying.
public string? RejectReason; // Rejected: BufferExpired | WidgetNotReady | …
}
public record ResendFailure
{
public string PlayerId;
public string WidgetId;
public int StrokeId;
public int FromSeq;
public string Reason;
}

See RequestResendAsync.

Validation

Pre-send payload validators run in editor builds when the relay reports RelayCapabilities.StrictPayloads. A failing validator throws InvalidPayloadException synchronously, instead of the relay silently dropping the message during a playtest.

PayloadSchemas.RegisterControlEvent("vibrate", payload =>
payload["duration_ms"]?.Type == JTokenType.Integer
? null
: "duration_ms is required and must be an int");

Production builds compile out the check; the relay remains authoritative.

Threading

Every callback fires on the Unity main thread. MainThreadDispatcher (internal) marshals events from the WebSocket reader thread. You can mutate Transform, instantiate prefabs, etc. directly from OnInput without dispatch.

The async methods (PromptAsync, RequestAsync, *Async variants) integrate with Unity’s async/await — they continue on the main thread by default. If you await from a background thread, capture the relevant context manually.

What’s not in the public API

By design, none of these are public:

  • ITransport and its implementations (CloudRelayTransport, LocalLanTransport). Implementation detail; the seam exists for engine-agnostic refactoring.
  • MainThreadDispatcher, ReconnectScheduler. Internal helpers.
  • The Json.cs Newtonsoft wrapper. Use Newtonsoft directly if you need it.
  • Generated protocol types under Runtime/Protocol/. Used by the SDK; not for game code. Use WidgetDefinitions to build widgets, not the raw types.