iOS App: Connect to Gateway, Pairing, Canvas & Troubleshooting
Learn how to install and use the Neura Market iOS app to connect to a Gateway, pair devices, access Canvas and other node capabilities, and troubleshoot common issues.
Read this when
- Pairing or reconnecting the iOS node
- Enabling or troubleshooting the direct Apple Watch node
- Running the iOS app from source
- Debugging gateway discovery or canvas commands
iPhone app builds are distributed through Apple channels once enabled for a release. You can also run local development builds directly from source.
What it does
- Establishes a WebSocket connection to a Gateway over a local network or tailnet.
- Makes node capabilities available: Canvas, Screen snapshot, Camera capture, Location, Talk mode, Voice wake, and opt-in Health summaries.
- Processes
node.invokecommands and forwards node status events. - Provides read-only workspace browsing for the selected agent from the Agents surface (Files): directory navigation, syntax-highlighted text previews, image previews, and share-sheet export. No write operations are allowed, and previews are size-limited by the gateway.
- Maintains a small read-only offline cache of recent chat sessions and transcripts per paired gateway: cold opens immediately display the last known transcript and refresh once the gateway responds, recent chats remain browsable while offline, and reset/forget clears the protected local cache.
- Stores text messages sent while offline in a durable per-gateway outbox (up to 50): queued bubbles appear in the transcript, flush in order on reconnection with idempotent retries, remain durable until canonical history confirms delivery, retry with backoff before showing a retry/delete action, and expire after 48 hours offline; reset/forget removes the queue along with the cache.
- Chat serves as the single text-and-voice interface. Chat actions can open the full Sessions screen without leaving Chat and can toggle assistant reasoning and tool activity visibility. Tap the microphone for draft dictation, open its menu to record a voice note, or use the inline Talk control for realtime voice; the Talk control animates from live microphone or playback level during listening or speaking.
- Settings -> OpenClaw opens a dedicated Gateway settings assistant when the operator connection has
operator.adminand the Gateway supportsopenclaw.chat. Its setup conversation remains separate from ordinary Chat, redacts secret replies locally, and moves to Chat only after you tap Open Chat. - Speaks assistant messages on demand: long-press a message in Chat and select Listen. The app plays supported gateway
tts.speakclips using the configured TTS provider and falls back to on-device speech when gateway audio is unavailable or cannot be played. Playback stops when the session switches or the app backgrounds.
Requirements
- A Gateway running on another device (macOS, Linux, or Windows via WSL2).
- Network path:
- Same LAN via Bonjour, or
- Tailnet via unicast DNS-SD (example domain:
openclaw.internal.), or - Manual host/port (fallback).
Quick start (pair + connect)
On first launch, the app guides you through a short pairing explainer and a permissions page (notifications, camera, microphone, photos, contacts, calendar, reminders, location). Every permission is optional and can be modified later in Settings -> Permissions, or in the iOS Settings app.
- Start an authenticated Gateway with a route your phone can reach. Tailscale Serve is the recommended remote path:
openclaw gateway --port 18789 --tailscale serve
For a trusted same-LAN setup, use an authenticated gateway.bind: "lan" instead. The default loopback bind cannot be reached from a phone. If the Gateway has not been configured yet, run openclaw onboard first so setup-code creation has a token or password auth path.
-
Open the Control UI, select Nodes, and click Pair mobile device on the Devices page. Full access is recommended and selected by default; choose Limited access only when you want to omit administrative Gateway controls, then click Create setup code.
-
In the iOS app, open Settings -> Gateway, scan the QR code (or paste the setup code), and connect.
If the setup code contains both LAN and Tailscale Serve routes, the app probes them in order and saves the first reachable endpoint.
Paired gateways remain in the Gateways list. The checkmark identifies the focused gateway; use the bolt control on another row to keep its operator session connected simultaneously. Switching focus does not disconnect other enabled gateways. Only the focused gateway receives the iPhone's capability-bearing node session, so camera, screen, location, and other device commands always have one unambiguous owner. iOS may suspend these foreground connections after the app enters the background.
-
The official app connects automatically. If Pending approval shows a request, review its role and scopes before approving it.
Settings → Gateway shows whether the saved operator connection has Full or Limited access. Plaintext LAN
ws://setup is automatically limited for bearer-token safety. If it is limited, configurewss://or Tailscale Serve, scan a new full-access code from Control UI oropenclaw qr, then reconnect to enable settings and upgrades.
The Control UI button requires an already paired session with operator.admin. As a terminal fallback, pick a discovered gateway in the iOS app (or enable Manual Host and enter host/port), then approve the request on the Gateway host:
openclaw devices list
openclaw devices approve <requestId>
If the app retries pairing with changed auth details (role/scopes/public key), the previous pending request is superseded and a new requestId is created. Run openclaw devices list again before approval.
Optional: if the iOS node always connects from a tightly controlled subnet, you can opt in to first-time node auto-approval with explicit CIDRs or exact IPs:
{
gateway: {
nodes: {
pairing: {
autoApproveCidrs: ["192.168.1.0/24"],
},
},
},
}
This is disabled by default. It applies only to fresh role: node pairing with no requested scopes. Operator/browser pairing and any role, scope, metadata, or public-key change still require manual approval.
- Verify connection:
openclaw nodes status
openclaw gateway call node.list --params "{}"
Health summaries
The iOS node can return an opt-in, read-only HealthKit aggregate for the current calendar day. iOS device consent and explicit Gateway command authorization are independent gates. See HealthKit summaries for setup, invocation, payload fields, privacy behavior, and troubleshooting.
By default, the Apple Watch companion keeps using the existing iPhone relay and does not need a separate Gateway pairing. Pair the Watch with the iPhone in Apple's Watch app, install OpenClaw from Watch app -> My Watch -> Available Apps, then open OpenClaw once on both devices.
Review command approvals
An operator connection with operator.admin, or a paired operator.approvals connection explicitly targeted by the Gateway, can review pending exec requests on iPhone. The approval card shows the Gateway's sanitized command preview, warning, host context, expiry, and only the decisions offered by that request. The paired Apple Watch receives the same reviewer-safe prompt through the existing iPhone relay and offers the compact allow-once/deny decision subset. Direct Watch Gateway mode does not carry approval prompts.
Approval state is shared with the Control UI and supported chat surfaces. The first committed answer wins. iPhone and Watch fetch the Gateway's canonical terminal record after another surface resolves the request, after a remote resolved notification, and whenever a resolve acknowledgement may have been lost. Actions stay unavailable until that readback confirms whether the request remains pending.
Approval ownership is bound to the selected Gateway. Switching gateways cannot apply an old prompt to the replacement connection. Gateways that predate the unified approval methods fall back to the shipped exec-specific methods; retained terminal state and richer cross-surface results require an updated Gateway.
Answer agent questions
Chat shows pending Gateway questions as native cards for operator connections with operator.questions (or operator.admin). Cards support single- and multi-select options, option descriptions, free-text Other answers, and an expiry countdown. Reconnects reload pending questions from the Gateway. A card locks when this device answers it, another surface answers it first, or the question expires or is cancelled.
Optional direct Apple Watch node
Direct mode gives the watch its own signed node identity and Gateway connection. Supported node commands continue to work over watch Wi-Fi or cellular while OpenClaw is active, even when the paired iPhone is unavailable.
Requirements:
- The iPhone must be linked to the Gateway using the
operator.adminscope. - The setup code must expose a
wss://Gateway endpoint whose certificate watchOS trusts; the watch polls the matchinghttps://origin. Unencrypted HTTP and trust models based solely on self-signed certificates or fingerprint verification are not supported. Consult Gateway-owned pairing for endpoint setup details. The watch cannot independently reach routes restricted to loopback, iPhone-only, or tailnet-only addresses. - Cellular functionality requires an Apple Watch with cellular hardware and an active service plan.
- OpenClaw must be running on the watch. Standard watchOS apps are prohibited by Apple from maintaining persistent WebSocket or TCP connections, so the direct node relies on short HTTPS polls and reconnects when the app comes back to the foreground. Refer to Apple's watchOS low-level networking guidance.
Setup:
- On the iPhone, go to Settings -> Apple Watch.
- Tap Enable Direct Gateway Connection.
- Launch OpenClaw on the watch before the temporary setup code expires.
- Confirm the dedicated Apple Watch entry showing
openclaw nodes status.
The setup code is a short-lived, node-only bootstrap credential; handle it with the same care as a password until it expires. It never contains the iPhone's stored Gateway password or token. After pairing completes, the watch saves its own device token and discards the bootstrap credential. Direct mode is limited to the commands listed below. Chat, Talk, approvals, and the existing watch.* notification flow continue to rely on the paired iPhone as a relay.
Direct watchOS node commands:
| Surface | Commands | Notes |
|---|---|---|
| Device | device.info, device.status | Watch identity, battery, thermal, storage, and network. |
| Notifications | system.notify | While the app is active; requires watch permission. |
Because watchOS does not expose WebKit to third-party apps, the direct watch node does not offer Canvas commands.
Relay-backed push for official builds
Official iOS builds distributed through Apple use an external push relay rather than publishing the raw APNs token to the gateway. The hosted relay at https://ios-push-relay.openclaw.ai is hardcoded as the base URL for App Store builds from the public release lane; this URL is not overridable and is not read from any configuration source.
Custom relay deployments require a separate iOS build and deployment path where the relay URL matches the gateway relay URL. The App Store release lane will never accept a custom relay URL. If you are building with a custom relay, configure the matching gateway relay URL:
{
gateway: {
push: {
apns: {
relay: {
baseUrl: "https://relay.example.com",
},
},
},
},
}
How the flow works:
- The iOS app registers with the relay using App Attest and a StoreKit app transaction JWS.
- The relay responds with an opaque relay handle and a send grant scoped to that registration.
- The iOS app retrieves the paired gateway identity (
gateway.identity.get) and includes it in the relay registration, so the relay-backed registration is delegated specifically to that gateway. - The app forwards the relay-backed registration to the paired gateway using
push.apns.register. - The gateway uses the stored relay handle for
push.test, background wakes, and wake nudges. - If the app later connects to a different gateway or a build with a different relay base URL, it performs a fresh relay registration instead of reusing the previous binding.
What the gateway does not need for this path: no deployment-wide relay token, no direct APNs key for official App Store relay-backed sends.
Expected operator flow:
- Install the official iOS app.
- Optional: set
gateway.push.apns.relay.baseUrlon the gateway only when using a deliberately separate custom relay build. - Pair the app to the gateway and wait for the connection to complete.
- The app publishes
push.apns.registeronce it has an APNs token, the operator session is connected, and relay registration succeeds. - After that,
push.test, reconnect wakes, and wake nudges can use the stored relay-backed registration.
Background alive beacons
When iOS wakes the app for a silent push, background refresh, or significant-location event, the app attempts a short node reconnect and then calls node.event with event: "node.presence.alive". The gateway records this as lastSeenAtMs/lastSeenReason on the paired node/device metadata only after the authenticated node device identity is known.
The app considers a background wake successfully recorded only when the gateway response includes handled: true. Older gateways may acknowledge node.event with { "ok": true }; that response is compatible but does not count as a durable last-seen update.
Compatibility note:
OPENCLAW_APNS_RELAY_BASE_URLstill works as a temporary env override for the gateway (gateway.push.apns.relay.baseUrlis the config-first path).- The App Store release build's push mode hardcodes the hosted relay host and never reads a relay-URL override, the
OPENCLAW_PUSH_RELAY_BASE_URLbuild-time env var only affects local/sandbox iOS build modes.
Authentication and trust flow
The relay exists to enforce two constraints that direct APNs-on-gateway cannot provide for official iOS builds:
- Only genuine OpenClaw iOS builds distributed through Apple can use the hosted relay.
- A gateway can send relay-backed pushes only for iOS devices that paired with that specific gateway.
Hop by hop:
iOS app -> gateway: the app pairs with the gateway through the normal Gateway auth flow, giving it an authenticated node session plus an authenticated operator session. The operator session callsgateway.identity.get.iOS app -> relay: the app calls the relay registration endpoints over HTTPS with App Attest proof plus a StoreKit app transaction JWS. The relay validates the bundle ID, App Attest proof, and Apple distribution proof, and requires the official/production distribution path, this is what blocks local Xcode/dev builds from using the hosted relay, since a local build cannot satisfy the official Apple distribution proof.gateway identity delegation: before relay registration, the app fetches the paired gateway identity fromgateway.identity.getand includes it in the relay registration payload. The relay returns a relay handle and a registration-scoped send grant delegated to that gateway identity.gateway -> relay: the gateway stores the relay handle and send grant frompush.apns.register. Onpush.test, reconnect wakes, and wake nudges, the gateway signs the send request with its own device identity; the relay verifies both the stored send grant and the gateway signature against the delegated gateway identity from registration. Another gateway cannot reuse that stored registration, even if it somehow obtains the handle.relay -> APNs: the relay owns the production APNs credentials and the raw APNs token for the official build. The gateway never stores the raw APNs token for relay-backed official builds; the relay sends the final push to APNs on behalf of the paired gateway.
Why this design was created: to keep production APNs credentials out of user gateways, avoid storing raw official-build APNs tokens on the gateway, allow hosted relay usage only for official OpenClaw iOS builds, and prevent one gateway from sending wake pushes to iOS devices owned by a different gateway.
Local and manual builds continue to use direct APNs. If you are testing those builds without the relay, the gateway still needs direct APNs credentials:
export OPENCLAW_APNS_TEAM_ID="TEAMID"
export OPENCLAW_APNS_KEY_ID="KEYID"
export OPENCLAW_APNS_PRIVATE_KEY_P8="$(cat /path/to/AuthKey_KEYID.p8)"
These are gateway-host runtime environment variables, not Fastlane settings. apps/ios/fastlane/.env only stores App Store Connect authentication details such as APP_STORE_CONNECT_KEY_ID and APP_STORE_CONNECT_ISSUER_ID; it does not configure direct APNs delivery for local iOS builds.
Recommended gateway-host storage, consistent with other provider credentials under ~/.openclaw/credentials/:
mkdir -p ~/.openclaw/credentials/apns
chmod 700 ~/.openclaw/credentials/apns
mv /path/to/AuthKey_KEYID.p8 ~/.openclaw/credentials/apns/AuthKey_KEYID.p8
chmod 600 ~/.openclaw/credentials/apns/AuthKey_KEYID.p8
export OPENCLAW_APNS_PRIVATE_KEY_PATH="$HOME/.openclaw/credentials/apns/AuthKey_KEYID.p8"
Do not commit the .p8 file or place it under the repo checkout.
Discovery paths
Bonjour (LAN)
The iOS app browses _openclaw-gw._tcp on local. and, when configured, the same wide-area DNS-SD discovery domain. Same-LAN gateways appear automatically from local.; cross-network discovery can use the configured wide-area domain without changing the beacon type.
Tailnet (cross-network)
If mDNS is blocked, use a unicast DNS-SD zone (choose a domain; example: openclaw.internal.) and Tailscale split DNS. See Bonjour for the CoreDNS example.
Manual host/port
Head to Settings, toggle Manual Host on, and provide the gateway host along with its port (default 18789).
Multiple gateways
The app maintains a record of every gateway it has previously paired with. This lets you change between them without needing to pair again:
- Go to Settings -> Gateway to view the Paired Gateways list, where the currently active gateway is highlighted. Selecting a different entry triggers a disconnect from the current sessions and a reconnect to the chosen gateway. When more than one gateway is paired, a quick-switch option appears next to the connection row.
- Each gateway stores its own credentials, TLS trust settings, per-gateway preferences, and cached conversation history. Switching gateways never mixes state between them, and push notifications follow whichever gateway is active.
- To remove a gateway, swipe it (or open its context menu) and choose Forget. This deletes its credentials, device tokens, TLS pin, and cached chats.
- Discovered gateways must be present on the local network to switch to them. For manually added gateways, reconnection uses the saved host and port.
Canvas + A2UI
The iOS node uses a WKWebView as its rendering surface. Drive it with node.invoke:
openclaw nodes invoke --node "iOS Node" --command canvas.navigate --params '{"url":"http://<gateway-host>:18789/__openclaw__/canvas/"}'
Notes:
- The Gateway canvas host delivers
/__openclaw__/canvas/and/__openclaw__/a2ui/through the Gateway HTTP server, which shares the same port asgateway.port(default18789). - The iOS node keeps the built-in scaffold as the default connected view. Both
canvas.a2ui.pushandcanvas.a2ui.resetrely on the bundled app-owned A2UI page. - Remote Gateway A2UI pages are view-only on iOS; native A2UI button actions are only accepted from bundled app-owned pages.
- To return to the built-in scaffold, use
canvas.navigateand{"url":""}.
Computer Use relationship
The iOS app functions as a mobile node surface, not as a Codex Computer Use backend. Codex Computer Use and cua-driver mcp manage a local macOS desktop through MCP tools. The iOS app, by contrast, exposes iPhone capabilities through OpenClaw node commands like canvas.*, camera.*, screen.*, location.*, and talk.*.
Agents can still control the iOS app via OpenClaw by invoking node commands, but those calls travel through the gateway node protocol and are subject to iOS foreground and background restrictions. For local desktop control, use Codex Computer Use; for iOS node functionality, refer to this page.
Canvas eval / snapshot
openclaw nodes invoke --node "iOS Node" --command canvas.eval --params '{"javaScript":"(() => { const {ctx} = window.__openclaw; ctx.clearRect(0,0,innerWidth,innerHeight); ctx.lineWidth=6; ctx.strokeStyle=\"#ff2d55\"; ctx.beginPath(); ctx.moveTo(40,40); ctx.lineTo(innerWidth-40, innerHeight-40); ctx.stroke(); return \"ok\"; })()"}'
openclaw nodes invoke --node "iOS Node" --command canvas.snapshot --params '{"maxWidth":900,"format":"jpeg"}'
Voice wake + talk mode
- Voice wake and talk mode can be enabled in Settings.
- OpenAI realtime Talk uses client-owned WebRTC when
talk.realtime.transportis set towebrtc. An explicitgateway-relayconfiguration stays owned by the Gateway. See Talk mode. - Talk-capable iOS nodes advertise the
talkcapability and can declaretalk.ptt.start,talk.ptt.stop,talk.ptt.cancel, andtalk.ptt.once. The Gateway permits those push-to-talk commands by default for trusted Talk-capable nodes. - iOS may suspend background audio, so treat voice features as best-effort when the app is not in the foreground.
Common errors
NODE_BACKGROUND_UNAVAILABLE: Bring the iOS app to the foreground (canvas, camera, and screen commands need this).A2UI_HOST_UNAVAILABLE: The bundled A2UI page was not accessible in the app WebView. Keep the app foregrounded on the Screen tab and try again.- Pairing prompt never appears: run
openclaw devices listand approve it manually. - Watch shows no iPhone state: confirm that the iPhone reports
watchPaired: trueandwatchAppInstalled: trueinwatch.status. If pairing is false, pair the Watch through Apple's Watch app. If installation is false, install the companion from My Watch -> Available Apps. After either change, open OpenClaw on the Watch once. Immediate reachability still requires both apps to be running, while queued updates can arrive later in the background. - Reconnect fails after a reinstall: the Keychain pairing token was cleared, so re-pair the node.