{
  "title": "Android App (Node)",
  "content": "* Role: companion node app (Android does not host the Gateway).\n* Gateway required: yes (run it on macOS, Linux, or Windows via WSL2).\n* Install: [Getting Started](/start/getting-started) + [Pairing](/gateway/pairing).\n* Gateway: [Runbook](/gateway) + [Configuration](/gateway/configuration).\n  * Protocols: [Gateway protocol](/gateway/protocol) (nodes + control plane).\n\nSystem control (launchd/systemd) lives on the Gateway host. See [Gateway](/gateway).\n\n## Connection Runbook\n\nAndroid node app ⇄ (mDNS/NSD + WebSocket) ⇄ **Gateway**\n\nAndroid connects directly to the Gateway WebSocket (default `ws://<host>:18789`) and uses Gateway-owned pairing.\n\n* You can run the Gateway on the “master” machine.\n* Android device/emulator can reach the gateway WebSocket:\n  * Same LAN with mDNS/NSD, **or**\n  * Same Tailscale tailnet using Wide-Area Bonjour / unicast DNS-SD (see below), **or**\n  * Manual gateway host/port (fallback)\n* You can run the CLI (`openclaw`) on the gateway machine (or via SSH).\n\n### 1) Start the Gateway\n\nConfirm in logs you see something like:\n\n* `listening on ws://0.0.0.0:18789`\n\nFor tailnet-only setups (recommended for Vienna ⇄ London), bind the gateway to the tailnet IP:\n\n* Set `gateway.bind: \"tailnet\"` in `~/.openclaw/openclaw.json` on the gateway host.\n* Restart the Gateway / macOS menubar app.\n\n### 2) Verify discovery (optional)\n\nFrom the gateway machine:\n\nMore debugging notes: [Bonjour](/gateway/bonjour).\n\n#### Tailnet (Vienna ⇄ London) discovery via unicast DNS-SD\n\nAndroid NSD/mDNS discovery won’t cross networks. If your Android node and the gateway are on different networks but connected via Tailscale, use Wide-Area Bonjour / unicast DNS-SD instead:\n\n1. Set up a DNS-SD zone (example `openclaw.internal.`) on the gateway host and publish `_openclaw-gw._tcp` records.\n2. Configure Tailscale split DNS for your chosen domain pointing at that DNS server.\n\nDetails and example CoreDNS config: [Bonjour](/gateway/bonjour).\n\n### 3) Connect from Android\n\n* The app keeps its gateway connection alive via a **foreground service** (persistent notification).\n* Open **Settings**.\n* Under **Discovered Gateways**, select your gateway and hit **Connect**.\n* If mDNS is blocked, use **Advanced → Manual Gateway** (host + port) and **Connect (Manual)**.\n\nAfter the first successful pairing, Android auto-reconnects on launch:\n\n* Manual endpoint (if enabled), otherwise\n* The last discovered gateway (best-effort).\n\n### 4) Approve pairing (CLI)\n\nOn the gateway machine:\n\nPairing details: [Gateway pairing](/gateway/pairing).\n\n### 5) Verify the node is connected\n\n* Via nodes status:\n  \n* Via Gateway:\n\n### 6) Chat + history\n\nThe Android node’s Chat sheet uses the gateway’s **primary session key** (`main`), so history and replies are shared with WebChat and other clients:\n\n* History: `chat.history`\n* Send: `chat.send`\n* Push updates (best-effort): `chat.subscribe` → `event:\"chat\"`\n\n### 7) Canvas + camera\n\n#### Gateway Canvas Host (recommended for web content)\n\nIf you want the node to show real HTML/CSS/JS that the agent can edit on disk, point the node at the Gateway canvas host.\n\nNote: nodes use the standalone canvas host on `canvasHost.port` (default `18793`).\n\n1. Create `~/.openclaw/workspace/canvas/index.html` on the gateway host.\n\n2. Navigate the node to it (LAN):\n\nTailnet (optional): if both devices are on Tailscale, use a MagicDNS name or tailnet IP instead of `.local`, e.g. `http://<gateway-magicdns>:18793/__openclaw__/canvas/`.\n\nThis server injects a live-reload client into HTML and reloads on file changes.\nThe A2UI host lives at `http://<gateway-host>:18793/__openclaw__/a2ui/`.\n\nCanvas commands (foreground only):\n\n* `canvas.eval`, `canvas.snapshot`, `canvas.navigate` (use `{\"url\":\"\"}` or `{\"url\":\"/\"}` to return to the default scaffold). `canvas.snapshot` returns `{ format, base64 }` (default `format=\"jpeg\"`).\n* A2UI: `canvas.a2ui.push`, `canvas.a2ui.reset` (`canvas.a2ui.pushJSONL` legacy alias)\n\nCamera commands (foreground only; permission-gated):\n\n* `camera.snap` (jpg)\n* `camera.clip` (mp4)\n\nSee [Camera node](/nodes/camera) for parameters and CLI helpers.",
  "code_samples": [
    {
      "code": "Confirm in logs you see something like:\n\n* `listening on ws://0.0.0.0:18789`\n\nFor tailnet-only setups (recommended for Vienna ⇄ London), bind the gateway to the tailnet IP:\n\n* Set `gateway.bind: \"tailnet\"` in `~/.openclaw/openclaw.json` on the gateway host.\n* Restart the Gateway / macOS menubar app.\n\n### 2) Verify discovery (optional)\n\nFrom the gateway machine:",
      "language": "unknown"
    },
    {
      "code": "More debugging notes: [Bonjour](/gateway/bonjour).\n\n#### Tailnet (Vienna ⇄ London) discovery via unicast DNS-SD\n\nAndroid NSD/mDNS discovery won’t cross networks. If your Android node and the gateway are on different networks but connected via Tailscale, use Wide-Area Bonjour / unicast DNS-SD instead:\n\n1. Set up a DNS-SD zone (example `openclaw.internal.`) on the gateway host and publish `_openclaw-gw._tcp` records.\n2. Configure Tailscale split DNS for your chosen domain pointing at that DNS server.\n\nDetails and example CoreDNS config: [Bonjour](/gateway/bonjour).\n\n### 3) Connect from Android\n\nIn the Android app:\n\n* The app keeps its gateway connection alive via a **foreground service** (persistent notification).\n* Open **Settings**.\n* Under **Discovered Gateways**, select your gateway and hit **Connect**.\n* If mDNS is blocked, use **Advanced → Manual Gateway** (host + port) and **Connect (Manual)**.\n\nAfter the first successful pairing, Android auto-reconnects on launch:\n\n* Manual endpoint (if enabled), otherwise\n* The last discovered gateway (best-effort).\n\n### 4) Approve pairing (CLI)\n\nOn the gateway machine:",
      "language": "unknown"
    },
    {
      "code": "Pairing details: [Gateway pairing](/gateway/pairing).\n\n### 5) Verify the node is connected\n\n* Via nodes status:",
      "language": "unknown"
    },
    {
      "code": "* Via Gateway:",
      "language": "unknown"
    },
    {
      "code": "### 6) Chat + history\n\nThe Android node’s Chat sheet uses the gateway’s **primary session key** (`main`), so history and replies are shared with WebChat and other clients:\n\n* History: `chat.history`\n* Send: `chat.send`\n* Push updates (best-effort): `chat.subscribe` → `event:\"chat\"`\n\n### 7) Canvas + camera\n\n#### Gateway Canvas Host (recommended for web content)\n\nIf you want the node to show real HTML/CSS/JS that the agent can edit on disk, point the node at the Gateway canvas host.\n\nNote: nodes use the standalone canvas host on `canvasHost.port` (default `18793`).\n\n1. Create `~/.openclaw/workspace/canvas/index.html` on the gateway host.\n\n2. Navigate the node to it (LAN):",
      "language": "unknown"
    }
  ],
  "headings": [
    {
      "level": "h2",
      "text": "Support snapshot",
      "id": "support-snapshot"
    },
    {
      "level": "h2",
      "text": "System control",
      "id": "system-control"
    },
    {
      "level": "h2",
      "text": "Connection Runbook",
      "id": "connection-runbook"
    },
    {
      "level": "h3",
      "text": "Prerequisites",
      "id": "prerequisites"
    },
    {
      "level": "h3",
      "text": "1) Start the Gateway",
      "id": "1)-start-the-gateway"
    },
    {
      "level": "h3",
      "text": "2) Verify discovery (optional)",
      "id": "2)-verify-discovery-(optional)"
    },
    {
      "level": "h3",
      "text": "3) Connect from Android",
      "id": "3)-connect-from-android"
    },
    {
      "level": "h3",
      "text": "4) Approve pairing (CLI)",
      "id": "4)-approve-pairing-(cli)"
    },
    {
      "level": "h3",
      "text": "5) Verify the node is connected",
      "id": "5)-verify-the-node-is-connected"
    },
    {
      "level": "h3",
      "text": "6) Chat + history",
      "id": "6)-chat-+-history"
    },
    {
      "level": "h3",
      "text": "7) Canvas + camera",
      "id": "7)-canvas-+-camera"
    }
  ],
  "url": "llms-txt#android-app-(node)",
  "links": []
}