docs/platforms/ios.md
Availability: iPhone app builds are distributed through Apple channels when enabled for a release. Local development builds can also run from source.
node.invoke commands and reports node status events.openclaw.internal.), oropenclaw gateway --port 18789
In the iOS app, open Settings and pick a discovered gateway (or enable Manual Host and enter host/port).
Approve the pairing 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.
openclaw nodes status
openclaw gateway call node.list --params "{}"
Official distributed iOS builds use the external push relay instead of publishing the raw APNs token to the gateway.
Official/TestFlight builds from the public App Store release lane use the hosted relay at https://ios-push-relay.openclaw.ai.
Custom relay deployments require a deliberately separate iOS build/deployment path whose relay URL matches the gateway relay URL. The public App Store release lane does not accept custom relay URL overrides. If you are using a custom relay build, set the matching gateway relay URL:
{
gateway: {
push: {
apns: {
relay: {
baseUrl: "https://relay.example.com",
},
},
},
},
}
How the flow works:
push.apns.register.push.test, background wakes, and wake nudges.What the gateway does not need for this path:
Expected operator flow:
gateway.push.apns.relay.baseUrl on the gateway only when using a deliberately separate custom relay build.push.apns.register automatically after it has an APNs token, the operator session is connected, and relay registration succeeds.push.test, reconnect wakes, and wake nudges can use the stored relay-backed registration.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 treats a background wake as 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_URL still works as a temporary env override for the gateway.OPENCLAW_PUSH_RELAY_BASE_URL for iOS builds.The relay exists to enforce two constraints that direct APNs-on-gateway cannot provide for official iOS builds:
Hop by hop:
iOS app -> gateway
gateway.identity.get.iOS app -> relay
gateway identity delegation
gateway.identity.get.gateway -> relay
push.apns.register.push.test, reconnect wakes, and wake nudges, the gateway signs the send request with its
own device identity.relay -> APNs
Why this design was created:
Local/manual builds remain on 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 env vars, not Fastlane settings. apps/ios/fastlane/.env only stores
App Store Connect / TestFlight auth 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:
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.
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.
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.
In Settings, enable Manual Host and enter the gateway host + port (default 18789).
The iOS node renders a WKWebView canvas. Use node.invoke to drive it:
openclaw nodes invoke --node "iOS Node" --command canvas.navigate --params '{"url":"http://<gateway-host>:18789/__openclaw__/canvas/"}'
Notes:
/__openclaw__/canvas/ and /__openclaw__/a2ui/.gateway.port, default 18789).canvas.a2ui.push and canvas.a2ui.reset use the bundled app-owned A2UI page.canvas.navigate and {"url":""}.The iOS app is a mobile node surface, not a Codex Computer Use backend. Codex
Computer Use and cua-driver mcp control a local macOS desktop through MCP
tools; the iOS app exposes iPhone capabilities through OpenClaw node commands
such as canvas.*, camera.*, screen.*, location.*, and talk.*.
Agents can still operate the iOS app through OpenClaw by invoking node commands, but those calls go through the gateway node protocol and follow iOS foreground/background limits. Use Codex Computer Use for local desktop control and this page for iOS node capabilities.
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"}'
talk capability and can declare
talk.ptt.start, talk.ptt.stop, talk.ptt.cancel, and talk.ptt.once;
the Gateway allows those push-to-talk commands by default for trusted
Talk-capable nodes.NODE_BACKGROUND_UNAVAILABLE: bring the iOS app to the foreground (canvas/camera/screen commands require it).A2UI_HOST_UNAVAILABLE: the bundled A2UI page was not reachable in the app WebView; keep the app foregrounded on the Screen tab and retry.openclaw devices list and approve manually.