Connection & Pairing
How the device reaches your relay, how it authenticates (or doesn't), and how a phone gets pointed at a session in the first place.
The connection config
Whether it comes from a layout's connection block or a pairing QR, the device
needs the same four things:
{
"url": "ws://192.168.1.50:8765",
"token": null,
"identity": {
"name": "Living Room iPad",
"channel": "home",
"role": "viewer",
"canBroadcast": false,
"canRoute": false
}
}
url— the relay WebSocket URL (ws://for LAN,wss://for the gateway).token— gateway auth token;null/omitted for a self-hosted relay.identity— the identify fields: name, channel, role, and capability flags.e2eeKey(optional) — a base64 symmetric key for end-to-end-encrypted forwarding; both ends must share it.
Two transports
Self-hosted relay (recommended to start)
Run the open-source MeshSocket relay on your machine/LAN. No gateway, no token, no account:
- The relay listens on
ws://<host>:<port>(default port8765). - The app permits non-TLS
ws://to loopback and private-IP addresses (an App-Store-sanctioned ATS exception,NSAllowsLocalNetworking). So a phone on the same Wi-Fi can connect tows://192.168.x.x:8765directly. - Remote/public servers should use
wss://(real TLS).
This is the zero-friction path for home automation, hobby dashboards, and development. Spinning one up is one command — see running-a-relay.
Connect+ gateway (hosted)
The hosted service wraps the same relay with an auth gateway: TLS (wss://),
per-account channel namespacing, connection-slot metering, and rate limiting.
Here a token is required:
- The device opens the socket, then waits for the gateway to admit it — the app shows "awaiting gateway…" during this step.
- A valid token ⇒ admitted and joined to the mesh under your account's namespace.
- An empty or invalid token ⇒ the socket stays open but you are parked — connected at the WebSocket level but never in the mesh, so you never appear in the roster and can't exchange frames. (The app may optimistically show "connected" after a settle window even while parked; treat roster membership, not the socket, as the truth.)
Use the gateway when the phone isn't on your LAN, or when you want the managed, metered service. Tokens are issued by the Connect+ validator.
Pairing a device
A device joins a session two ways:
- A layout with a
connectionblock — load the layout; it connects automatically using the embedded config. - Scanning a pairing QR — the QR encodes a JSON payload:
json
{ "url": "ws://192.168.1.50:8765", "token": "", "channel": "editor",
"role": "viewer", "k": "<optional base64 e2ee key>" }
The app decodes url + channel (required), token, role (default
viewer), and k (the E2EE key, optional), then starts a session. This is how
the editor/MCP pair a phone for live authoring.
Roles in practice
| Role | Typical use | Caps (defaults) |
|---|---|---|
viewer |
A dashboard that only displays | listen only |
controller |
A remote that sends actions | broadcast/route |
hub / node |
Your server | broadcast/route |
editor |
A layout-authoring client | broadcast/route/monitor |
Roles set capability defaults at the relay, but you can always set
canBroadcast/canRoute/can_monitor explicitly. A pure dashboard should be a
viewer so it can't accidentally talk; your server should declare the caps it
needs (can_broadcast to push data, can_route to send routed requests).
Live-edit vs. connected layouts
- A connected layout is a finished layout the device runs against your relay for real use.
- A live-edit session is a transient authoring mode (started by a QR scan from an editor): the device renders an editor-pushed layout, re-rendering on each push, and exposes read-back responders so the editor can see what's on screen. Covered in Live Editing & the MCP Authoring Loop.
Next: build the backend — Anatomy of a CAR-TER Server.