Skip to main content
Use the published Gateway packages to build operator dashboards, WebChat clients, and other third-party applications. This guide covers the client lifecycle around the wire contract: authentication, capabilities, reconnect recovery, history, subscriptions, and version upgrades. For frame shapes, the handshake, errors, and the complete method surface, read the Gateway protocol specification.

Install the packages

These packages ship with OpenClaw release trains. During the initial rollout, npm may return E404 until the first package-bearing OpenClaw release is published; install them only after the registry pages below resolve.
  • @openclaw/gateway-protocol provides schemas, runtime validators, TypeScript types, client identity and capability registries, structured error readers, and protocol version constants. Its npm tarball also includes the generated protocol.schema.json machine-readable contract.
  • @openclaw/gateway-client is the reference connection implementation. Import the package root for the Node client and @openclaw/gateway-client/browser for the browser-safe protocol, device-auth, and reconnect helpers.
The Node entry owns its WebSocket transport. A browser host supplies a WebSocket adapter plus persistent storage and signing callbacks for the device identity and device token.

Choose scopes and pair the device

A full interactive chat client that also renders approval prompts should request role: "operator" with these scopes: Add operator.questions only if the client handles interactive questions, operator.pairing only if it manages paired devices or nodes, and operator.admin only for administrative operations such as config.patch. The operator scopes reference defines the complete method and approval-time rules. Do not create a per-client bearer token by hand-editing openclaw.json. Configure the Gateway’s shared bootstrap authentication with openclaw configure --section gateway or the openclaw onboard --gateway-auth ... options, then let device pairing mint the client token:
  1. Persist an Ed25519 device identity in the client.
  2. Wait for connect.challenge, sign the challenge-bound device payload, and send connect with the requested operator role, scopes, and the shared Gateway token or password for bootstrap authentication.
  3. If the Gateway returns structured PAIRING_REQUIRED details, show the request ID and pause or retry according to error.details.recommendedNextStep.
  4. On the Gateway host, review the request with openclaw devices list, then approve that exact current request with openclaw devices approve <requestId>.
  5. Reconnect and persist hello-ok.auth.deviceToken with the negotiated role and scopes. Use that device token for later connections.
Scope or role upgrades create a new pending pairing request. Token rotation cannot expand the approved pairing contract. See the Devices CLI for approval, rotation, and revocation commands. connect.params.caps describes optional behavior the client can consume. It does not grant authorization. Import names from GATEWAY_CLIENT_CAPS instead of duplicating string literals:
The current registry contains approvals, exec-approvals, inline-widgets, run-tool-bindings, session-scoped-events, plugin-approvals, task-suggestions, terminal-offset-seq, tool-events, and ui-commands. Advertise only capabilities the client actually implements.
tool-events gates live tool-execution streaming. The Gateway registers only connections that advertise this capability as recipients for a run’s structured tool events. Without it, the connection receives no live tool events and the handshake does not report an error.
Capability-gated agent tools are a separate use of the same declaration. If an agent tool requires a client capability, the Gateway omits that tool unless the originating client advertised every required capability.

Recover state after reconnect

Treat every successful reconnect as a new projection over durable history and current in-memory run state:
  1. Re-establish sessions.subscribe and the selected session’s sessions.messages.subscribe subscription.
  2. Call chat.history for the selected sessionKey and replace local persisted rows with the returned messages projection.
  3. If inFlightRun is present, adopt its runId, buffered text, and optional plan. Adopt the run even when text is empty.
  4. Read sessionInfo.hasActiveRun and sessionInfo.activeRunIds. Prefer exact membership in activeRunIds when deciding whether a retained run still owns the streaming UI. A true hasActiveRun with no listed ID can represent another active runtime projection.
  5. Reconcile subsequent agent events by payload.runId and payload.seq. Maintain the highest accepted sequence independently for each run, ignore an already-seen or lower sequence, and treat a forward gap as a reason to reload authoritative history.
The outer event frame also has an optional seq, which orders events on the current WebSocket connection. It resets with a new connection. The seq inside an agent event payload is assigned per run and orders that run’s lifecycle, assistant, plan, tool, and other stream events.

Use history metadata and stable anchors

Rows returned by chat.history can carry an __openclaw metadata envelope:
  • id is the transcript entry identity. Use it for anchored history requests, but not as a unique display-row key.
  • seq is the positive transcript-record sequence. One stored record can project into more than one display row, so keep siblings with the same id and sequence together.
  • kind identifies synthetic rows. A compaction boundary uses kind: "compaction" and may include tokensBefore and tokensAfter when a matching checkpoint recorded those metrics.
Page backward with the response’s hasMore and nextOffset values. Numeric offsets describe the current transcript projection, so do not persist them as long-lived bookmarks across reset or compaction. Persist __openclaw.id instead. To restore around a known row, call chat.history with messageId and the sessionId that returned it. The Gateway can resolve that anchor from reset archive history; anchored responses intentionally omit numeric paging metadata.

Subscribe instead of polling usage

Load the initial catalog with sessions.list, then call sessions.subscribe once per connection. Merge sessions.changed events by sessionKey. Session change payloads can carry live inputTokens, outputTokens, totalTokens, totalTokensFresh, contextTokens, estimatedCostUsd, response-usage settings, and active-run state. Some change notifications are only invalidation signals. If an event omits the row fields your view needs, refresh sessions.list. Do not poll usage.cost or sessions.usage to keep a live session list current; reserve those methods for on-demand aggregate or detailed reports.

Backfill exec approvals

A client with operator.approvals should install its event listener as soon as hello-ok completes, then call exec.approval.list to backfill requests that predate the connection. Reconcile the list and live exec.approval.requested / exec.approval.resolved events by approval ID so a transition racing the list request is neither lost nor resurrected.

Track protocol versions

The current wire version is 4. General operator and WebChat clients must negotiate the exact current version with minProtocol: 4 and maxProtocol: 4. Only authenticated node clients and lightweight probes have the N-1 acceptance window, currently protocol 3 through 4. Protocol changes are additive first. protocol.schema.json includes since release-vintage metadata and required scope metadata for core methods, but a wire version bump is still an explicit breaking event for third-party clients. Pin the package versions you test, upgrade the client and Gateway together when the wire version changes, and review the OpenClaw changelog before each upgrade.