Android Companion App: Pairing, Chat, Voice, and Commands

Covers the OpenClaw Android companion node app: pairing with a Gateway, connection recovery, chat, voice, and device commands. For users installing via Google Play or a signed APK.

Read this when

  • Pairing or reconnecting the Android node
  • Debugging Android Gateway discovery or auth
  • Mirroring or controlling an Android device from a remote Mac
  • Verifying chat history parity across clients

Note

A signed standalone APK for sideloading is offered on selected GitHub Releases, and the official Android app can be downloaded from Google Play. Not all releases ship the APK or its checksum. To locate and verify both files, see Install outside Google Play. This app acts as a companion node and needs a running OpenClaw Gateway. Source: apps/android (build instructions).

Support snapshot

  • Role: companion node app (the Gateway is not hosted on Android).
  • Gateway required: yes (run it on macOS, Linux, or Windows via WSL2).
  • Install: Google Play or OpenClaw-Android.apk from a GitHub Release that lists both required assets (see Install outside Google Play), then Getting Started for the Gateway, then Pairing.
  • Gateway: Runbook + Configuration.
  • Pick an agent in the sidebar and its credential status appears under Settings → Providers & Models. Whenever the Gateway publishes model, credential, or config changes, the page refreshes. To check model availability again, use Refresh. Choices for available models stay visible while refreshes run in the background. Once recovery succeeds, the refresh warning goes away on its own.
  • Sessions awaiting an answer or approval get marked in the sidebar, including ones that are inactive or inside collapsed groups. To read the oldest pending request plus how many more requests of the same kind exist, tap the attention icon, hover over it, or focus it with a keyboard. The indicator disappears once requests resolve, are canceled, or expire. Answer drafts are never included in question previews.
  • Cron sessions and system-created checks are kept out of ordinary chat lists by the sidebar and the recent Threads view, and saved pins are left untouched. The selected conversation remains reachable; named work and human-created background conversations stay visible. To locate and reopen automation and system conversations, including chats pinned earlier, open Threads → Automations. This filter applies to the view only and is not stored as a setting. Scheduled jobs and their recent run summaries appear under Sidebar → Pages pencil → Automations. Sessions lacking creation metadata stay visible instead of being classified by their titles.
  • Long-press a thread that qualifies and pick Snooze: In 1 hour, In 3 hours, This evening (18:00 local, when more than one hour away), Tomorrow (09:00 local), or Next week (next Monday at 09:00 local, omitted on Sundays). While snoozed, sessions are hidden from Recent, Current, and sidebar recents. Their wake times are listed in the Snoozed pill; Wake session returns one early. A session wakes when its time expires, a real inbound message arrives, or a run completes; pinning or archiving also clears snooze. Snooze is synced through the Gateway and never halts runs, messages, or automations. Sessions that are archived, child, or protected cannot be snoozed.
  • Settings → OpenClaw launches a dedicated Gateway settings assistant when the operator connection has operator.admin and the Gateway supports openclaw.chat. Its setup conversation is kept apart from ordinary Chat, secret replies are redacted locally, and it moves to Chat only after you tap Open Chat.

For secret prompts, its reply field switches to masked input. If a prompt change closes the keyboard, tap it again. Sensitive replies are sent by Android without trimming, and unsent drafts are cleared when you leave this page or background the app.

At the end of the settings conversation, new replies stay in view. To read earlier steps, scroll up without being pulled away, then tap Jump to latest to resume following. Following also resumes when resizing the window makes the whole conversation visible. Restart, when offered after an error, opens a new conversation at its latest reply.

System control (launchd/systemd) runs on the Gateway host, see Gateway.

Simultaneous Gateway sessions

Pair each Gateway once, then open Settings → Gateway. A checkmark identifies the focused Gateway, and each switch decides whether a non-focused Gateway's operator session stays connected. While the app is in the foreground, enabled Gateways reconnect on their own, so changing focus does not tear down the others. Only the focused Gateway owns the Android node session and device capabilities; this stops simultaneous Gateways from sending camera, location, screen, or notification commands to the same phone. Once the app leaves the foreground, Android may suspend the secondary connections.

The sidebar defaults to Home → Threads → Skills → Overview. Personalized orders and pinned work pages that already exist are preserved; Pages pencil → Edit pinned items → Reset pinned items brings back these defaults. All settings, including while offline, open from the Settings gear next to the Gateway selector. Settings lives in the footer, not in the Pages menu or the pin editor.

While the sidebar is visible and the app is in the foreground, expanded session catalogs refresh every two minutes. Returning to the sidebar or reconnecting refreshes active catalogs right away. After initial discovery, polling pauses once every catalog is collapsed; expanding the first catalog resumes it at once. While polling is active, failed requests and source errors retry every 30 seconds.

To open Agents, Automations, Usage, Skills, Skill Workshop, Dreaming, Terminal, or Desktop (when available), use the pencil beside Pages. Frequently used pages can be pinned with Edit pinned items. Search also keeps these work pages reachable; Settings covers this phone, connections, configuration, and diagnostics. Icon meanings are shared across Settings, sidebar, search, and detail headers with the Web UI. Connection and approval states are spelled out instead of shown as unlabeled green or gray dots.

When no Gateways are saved, the sidebar footer's Gateway selector opens Add Gateway; when one is saved, it opens Gateway settings. If several Gateways are saved, it opens a native quick picker listing the focused route with a checkmark, Add Gateway, and Manage Gateways.

Add Gateway opens the QR scanner without disconnecting the current Gateway or restarting onboarding. A setup code can also be entered, a QR image chosen, or a Gateway URL typed in manually. A valid code opens a confirmation; the handoff begins only when you tap Connect. Cancel returns to the previous screen, leaving the current conversation, drafts, attachments, and saved Gateways as they were. When you add a Gateway that is already saved, its existing connection settings are used; to replace its setup, use Manage Gateways. Offline entries that are saved stay listed; connection status is separate from selection.

In Manage Gateways, tap Rename to set a name used only on this phone. That name shows up in the sidebar and picker and survives switching Gateways, reconnecting, app restarts, and discovery updates. Gateways sharing a name are still told apart by their secondary address. To restore the default, clear the name. Renaming leaves the Gateway's address, identity, and saved credentials unchanged. If you downgrade to an older Android build, that build can discard these local names when it starts and rewrites the registry. Gateway addresses and credentials are not affected; after you upgrade again, pick the local names again if needed.

When you switch away and back, unsent text and finished attachments stay with their Gateway, agent, and session. Before using the quick picker, finish recording, stop dictation or Talk, and let media imports or pending send admission complete. During handoff the composer stays protected, but a committed offline Gateway remains usable without waiting for a network connection.

Dictation and attachments

To dictate, tap the composer microphone. While you speak, the composer shows whether recognition is starting, listening, or transcribing, along with an interim transcript. Your draft receives only the final transcript. Tap Stop to end listening, or Cancel during starting or transcribing to discard that attempt. Recognition errors leave your existing draft intact and explain how to retry.

Once photos and files are picked or shared, Preparing attachments… remains visible until they are ready. Send stays disabled while preparation runs. Queuing message… covers local send admission; delivery or any failure then shows in the message's outbox status. Offline messages still go through the durable queue.

Wear OS companion

The Wear OS companion relies on the authenticated Gateway connection of the paired Android phone. Gateway credentials are never sent to the watch, nor stored on it. From the watch you can pick agents and sessions, read bounded transcripts, send typed or dictated replies, abort a run in progress, launch realtime Talk in the chosen session, and connect or disconnect the paired phone's Gateway. Local reply notifications, dark or light appearance, and optional automatic speech for replies are also available. Agent and Gateway controls are capability-negotiated so that staggered phone/watch updates keep working. Realtime Talk sends microphone and playback audio over a temporary Wear OS Data Layer channel, and it stops once the selected phone, the Gateway connection, or the audio channel is lost.

Install outside Google Play

Some GitHub Releases ship a universal OpenClaw-Android.apk together with an OpenClaw-Android-SHA256SUMS.txt. The APK is produced from the release tag, signed with the OpenClaw Android release key, and comes with GitHub Actions provenance. Android assets may be attached after a release has already gone public. Choose a release based on the assets it lists, not on the newest Gateway release tag.

To list published releases that carry both required assets:

gh api --paginate "repos/openclaw/openclaw/releases?per_page=50" \
  --jq '.[] | select(.draft | not) | {
    tag: .tag_name,
    apk: ([.assets[].name] | any(. == "OpenClaw-Android.apk")),
    checksum: ([.assets[].name] | any(. == "OpenClaw-Android-SHA256SUMS.txt"))
  } | select(.apk and .checksum)'

Choose a release that lists both assets, then download and verify that exact tag before sideloading:

release_tag=vYYYY.M.PATCH
gh release download "$release_tag" \
  --repo openclaw/openclaw \
  --pattern OpenClaw-Android.apk \
  --pattern OpenClaw-Android-SHA256SUMS.txt
sha256sum --check OpenClaw-Android-SHA256SUMS.txt
gh attestation verify OpenClaw-Android.apk \
  --repo openclaw/openclaw \
  --signer-workflow openclaw/openclaw/.github/workflows/android-release.yml \
  --source-ref "refs/tags/${release_tag}" \
  --deny-self-hosted-runners

Should no release list both files, use Google Play, or build from source with a signing identity of your own.

Warning

Standalone APK installs and Google Play use separate update channels, and their signing identities may differ. Switching channels may force Android to uninstall the existing app first, which wipes its local app data. For normal updates, remain on a single channel.

Note

Producing a release artifact (APK or app bundle) from source or a fork calls for your own Android signing identity. Debug builds are signed with an automatically generated debug key. The official OpenClaw release key is not shipped in the repository. How to generate and configure a signing key for release builds is covered in Sign your app.

App and Gateway compatibility

Release version numbers on the Android app and the Gateway do not have to match. What determines connection compatibility is the set of Gateway protocol versions each side supports, not the release tag the APK came from.

Chat and UI actions travel over one connection (the operator connection), while device capabilities use another (the node connection). The operator connection has to support the Gateway's current protocol. Within the documented compatibility window, an authenticated node connection may still use the previous protocol; chat and UI actions get no such exception. Current versions and node capability restrictions are listed in Gateway protocol versioning.

A successful pairing does not mean every feature will work across any arbitrary app/Gateway version combination. New features may need updates on both sides. When a connection reports protocol mismatch, review the protocol requirements and the available updates for the app and the Gateway. For sideloaded apps, follow the APK selection and verification steps above instead of assuming the newest Gateway release bundles a newer app.

Mirror and control Android from a remote Mac

scrcpy shows an Android screen in a macOS window and passes keyboard and pointer input through Android Debug Bridge (ADB). This workflow runs on the operator side and is separate from the OpenClaw node connection. It helps when the Android device and the Mac sit in different places but share a private Tailscale network.

Before you begin

  • Install Tailscale on both the Android device and the Mac, then join both to the same tailnet.

  • On Android, turn on Developer options and USB debugging. In Android 16, Wireless debugging lives under Settings → System → Developer options. See Android developer options.

  • Install scrcpy and ADB on the Mac:

    brew install scrcpy
    brew install --cask android-platform-tools
    
  • For the first connection, the Android device must be at hand. Before any Mac can control the device, Android has to approve that Mac's ADB key.

Enable ADB over TCP

During initial setup, attach the Android device by USB to a trusted computer and approve the debugging prompt it shows. Then run:

adb devices
adb tcpip 5555

USB can be disconnected at this point. Should port 5555 stop listening after a reboot or a debugging reset, repeat this local setup step. On Android 11 and later, initial trust can also be established through Wireless debugging → Pair device with pairing code and adb pair.

Allow only the controller Mac

When tailnet grants are restrictive, the controller Mac must be explicitly allowed to reach TCP port 5555 on the Android device. Add a narrow rule to the tailnet policy, substituting the two devices' stable Tailscale IPs for the example addresses:

{
  grants: [
    {
      src: ["<remote-mac-tailnet-ip>"],
      dst: ["<android-tailnet-ip>"],
      ip: ["tcp:5555"],
    },
  ],
}

Host aliases and other selectors are described in Tailscale grants. Never grant this port to the public internet or expose it through Funnel: an authorized ADB client gains broad control over the device.

Connect and start mirroring

On the remote Mac:

adb connect <android-tailnet-ip>:5555
adb devices
scrcpy --serial <android-tailnet-ip>:5555

The first adb connect issued from this Mac triggers an authorization dialog on Android. Unlock the device, check the key fingerprint, and choose Always allow from this computer only if the Mac is trusted. A successful adb devices entry ends in device; if you see unauthorized, the on-device prompt has not been approved yet.

After the scrcpy window appears, operate it directly or drive it with a macOS screen-automation tool such as Peekaboo. Display and input are carried by scrcpy; Tailscale only supplies the private network path.

Troubleshooting

  • Connection timed out: check the tailnet grant for TCP 5555. A successful tailscale ping only proves peer reachability, not that policy allows this TCP port. Test from the Mac with nc -vz <android-tailnet-ip> 5555.
  • unauthorized: unlock Android and approve the remote Mac's ADB key, or delete the stale workstation under Wireless debugging → Paired devices and pair it again.
  • Connection refused: reconnect locally and run adb tcpip 5555 once more.
  • More than one device listed: keep the explicit --serial <android-tailnet-ip>:5555 argument.

When you are done, close scrcpy and disconnect ADB:

adb disconnect <android-tailnet-ip>:5555

Connection runbook

Android node app ⇄ (mDNS/NSD + WebSocket) ⇄ Gateway

Android talks to the Gateway WebSocket directly and pairs through the device pairing flow (role: node).

For Tailscale or public hosts, Android insists on a secure endpoint:

  • Preferred: Tailscale Serve / Funnel with https://<magicdns> / wss://<magicdns>
  • Also supported: any other wss:// Gateway URL backed by a real TLS endpoint
  • Cleartext ws:// still works on private LAN addresses / .local hosts, and on localhost, 127.0.0.1, and the Android emulator bridge (10.0.2.2); non-loopback setups automatically get limited operator access

Prerequisites

  • A Gateway running on another machine (or reachable over SSH).
  • The Android device/emulator must be able to reach the Gateway WebSocket:
    • Same LAN with mDNS/NSD, or
    • Same Tailscale tailnet via Wide-Area Bonjour / unicast DNS-SD (see below), or
    • Manual Gateway host/port (fallback)
  • Tailnet/public mobile pairing does not work with raw tailnet IP ws:// endpoints. Use Tailscale Serve or another wss:// URL instead.
  • The openclaw CLI on the Gateway machine (or over SSH), for approving pairing requests.

1. Start the Gateway

Run an authenticated Gateway. If none is configured yet, run openclaw onboard first to set up a token or password.

For a trusted same-LAN setup, persist the LAN bind before starting:

openclaw config set gateway.bind lan
openclaw gateway --port 18789

Bare-metal and virtual-machine hosts default to loopback, which a phone cannot reach. Detected containers may default to auto instead. For this setup, set the bind explicitly.

Prefer the config command over --bind lan on its own: a startup-only flag does not alter the configuration that a separate openclaw qr command reads. With no other configured URL route, setup-code creation still sees loopback and refuses to mint a code.

Run openclaw gateway status. The Gateway: line it prints should contain bind=lan (0.0.0.0) and port=18789.

To reach Android remotely, pick managed Tailscale Serve rather than binding to the LAN. Store its settings in config so that setup-code creation can reuse the same route:

openclaw config set gateway.bind loopback
openclaw config set gateway.tailscale.mode serve
openclaw gateway --port 18789

Tailscale has to be installed and logged in. Managed Serve and Funnel both need loopback binding, so clear gateway.bind=lan before you switch to either of them. Serve and password-protected Funnel setup are covered under Tailscale.

Android then gets a secure wss:// / https:// endpoint. A plain gateway.bind: "tailnet" setup will not suffice for pairing a remote Android device the first time, unless TLS is terminated separately as well.

2. Verify discovery (optional)

On the Gateway machine, run:

dns-sd -B _openclaw-gw._tcp local.

Additional debugging notes live at Bonjour.

When a wide-area discovery domain is configured too, compare its output with:

openclaw gateway discover --json

One pass of that command prints local. together with the wide-area domain you configured, and it relies on the resolved service endpoint rather than TXT-only hints.

Cross-network discovery via unicast DNS-SD

Android NSD/mDNS discovery cannot cross network boundaries. Should the Android node and the Gateway sit on different networks yet be joined through Tailscale, switch to Wide-Area Bonjour / unicast DNS-SD. Discovery by itself will not carry a tailnet/public Android pairing: the route that was discovered still requires a secure endpoint (wss:// or Tailscale Serve):

  1. On the Gateway host, stand up a DNS-SD zone (the example uses openclaw.internal.) and publish the _openclaw-gw._tcp records.
  2. In Tailscale split DNS, point the domain you chose at that DNS server.

The example CoreDNS config and further details are in Bonjour.

3. Connect from Android

Generate a setup code either in the Control UI under Devices → Pair device, or with openclaw qr.

Android's Scan QR or setup code / Enter setup code accept that mobile setup code and its QR. Do not confuse it with the gateway join URL produced by openclaw devices join-code (https://…/j/<code>), which is used to enroll a headless node host through openclaw connect. Android setup rejects a pasted join URL or bare join code, so create a new mobile QR/setup code using openclaw qr.

An explicit --url or --public-url override takes precedence. When none is given, setup-code URL selection follows this order:

  1. plugins.entries.device-pair.config.publicUrl, unless a remote preference was requested.
  2. gateway.remote.url, when it is explicitly preferred.
  3. Managed Tailscale Serve or Funnel.
  4. The ordinary gateway.remote.url setting.
  5. Any usable configured bind, for example the LAN bind from step 1.

openclaw qr --remote chooses remote credentials, disregards the configured device-pair publicUrl, and gives gateway.remote.url priority over managed Tailscale. See QR.

URL selection never checks whether the network is actually reachable. A resolution error halts setup-code creation rather than falling back to a lower-priority route. If the Gateway is loopback-only and has neither a configured URL nor a managed Tailscale route, no code will be minted.

Inside the Android app:

  • A foreground service (with a persistent notification) keeps the app's Gateway connection alive.
  • At first-run setup, pick Scan QR or setup code or Set up manually.
  • Once paired, select which phone permissions to grant. Where the Gateway requires node approval, check the requested capabilities and press Approve access and continue when it appears. Setup completes after the app confirms the approval. If no prompt appears, run the Gateway approval commands shown, then press I have approved.
  • Later, go to Settings → Gateway. With Add Gateway you can scan or paste a setup code, or attach to a Gateway that was discovered.
  • When discovery is blocked, use Manual Gateway on the same page: supply the host and port, choose Connection security, then press Save & Connect. Private LAN hosts accept ws://; for Tailscale/public hosts, pick Secure (TLS) together with a wss:// / Tailscale Serve endpoint.

Gateway tokens, bootstrap tokens, passwords, and setup codes appear masked and allow pasting. The app asks for password input with autocorrection turned off, yet it cannot control how a third-party keyboard stores or learns from what you type.

Once the first pairing succeeds, Android reconnects automatically at launch to the active paired Gateway (discovered Gateways are best-effort and must be visible on the network).

Temporary connection drops are retried by Android on its own. To make a fresh attempt against the saved endpoint, open Settings → Gateway and press Reconnect. Disconnect tears down the connections and blocks automatic reconnect for the current app session, though the pairing itself is kept. Retries may pause on authentication or pairing errors until the reported problem is resolved.

Gateway summary rows wrap when labels and values are long. Press Instance ID under Settings → Gateway to copy this phone's full identifier.

Official setup codes enroll Android as a node and, by default, grant full Gateway operator access over wss://. A plaintext non-loopback ws:// setup falls back to limited access automatically to protect the bearer token. Settings → Gateway displays Full or Limited access. On a limited connection, set up wss:// or Tailscale Serve, create a new full-access code in Control UI or with openclaw qr, then scan or paste it on that page and reconnect. To get the reduced profile deliberately, pick Limited access in Control UI or run openclaw qr --limited.

Manage paired Gateways

Every Gateway the app has paired with is kept in a registry, so operator sessions can stay connected and you can move focus without pairing again:

  • Settings → Gateway shows paired Gateways under the Gateways section, and a checkmark marks the focused one. Tap a different entry to focus it; the other enabled operator sessions stay connected.
  • Each switch decides whether that non-focused Gateway remains connected while the app is in the foreground. The focused Gateway stays enabled and holds the phone's node connection and device capabilities.
  • Per Gateway, the app stores credentials, device tokens, TLS trust, chat history, and queued offline messages. Switching focus never blends state across Gateways, and a message queued while offline reaches only the Gateway it was written for.
  • Forget deletes a Gateway's registry entry along with its credentials, device tokens, TLS pin, and cached chats.

When a conversation notification is opened or replied to, its saved Gateway reconnects if needed. A target that is already connecting or connected is kept. Replies wait until that target connection is ready, including any TLS approval it requires. If the target is gone, opening the notification displays Gateway unavailable and opens Gateway settings, without disconnecting any other Gateway. Before a notification reply joins the durable send queue, disconnect is checked once more; input already queued keeps its usual recovery behavior.

Reply queued means the reply reached the durable send queue, not that it was delivered. The notification holds a private preview of the submitted text and offers Open conversation. If the reply status is unclear, open the conversation and check before sending again; no second Reply action is offered in the notification. Feedback updates only the newest notification for that conversation, so an older result cannot overwrite a newer notice. A notification posted before an app update can still send replies. Its result neither rewrites nor dismisses that notification, so open the conversation to check the status.

The Channels, Dreaming, Health logs, Skills, and Usage pages retain their last loaded data while refreshing. If the first load fails, an error appears instead of empty counts or default health values. When refreshes overlap, only the newest request updates the page's data, error, and progress. Disconnecting clears the summaries on display.

On Health, Chat: Not ready indicates that chat health is unconfirmed or that its check failed; the Gateway itself may still be Online. The chat header's accessibility status uses the same readiness wording. To check again, use Refresh chat in chat actions; Refresh Logs reloads logs only. The Overview's Gateway card shows connection status and flags known issues, not overall system health.

Presence alive beacons

Once the authenticated node session is connected, and when the app goes to the background while the foreground service is still connected, Android invokes 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.

Only when the Gateway reply carries handled: true does the app treat the beacon as recorded. If a Gateway answers node.event with { "ok": true } and omits the handled field, it is compatible, though such a reply does not qualify as a durable last-seen update.

4. Approve pairing (CLI)

Run this on the Gateway host:

openclaw devices list
openclaw devices approve <requestId>
openclaw devices reject <requestId>

For pairing instructions, see Pairing.

Optional: when the Android node always reaches the Gateway from a strictly controlled subnet, you may enable first-time node auto-approval using explicit CIDRs or exact IPs:

{
  gateway: {
    nodes: {
      pairing: {
        autoApproveCidrs: ["192.168.1.0/24"],
      },
    },
  },
}

This option is off by default. It covers only fresh role: node pairing that requests no scopes. Operator or browser pairing, along with any change to role, scope, metadata, or public key, still needs manual approval.

5. Verify the node is connected

openclaw nodes status
openclaw gateway call node.list --params "{}"

6. Chat + history

The draft gets a full-width row of its own, placed above the attachment and voice/send controls, so bigger text and narrow screens never crowd it in between buttons. The empty hint is kept to a single line; a draft can grow to six lines and then scrolls when room runs short. Side gutters in the composer are narrower than those of the transcript. +, model, and reasoning sit together on the left; the microphone and Talk/send share one row on the right. Controls stay 48dp tall; on very short views the icon buttons narrow to free space for Details while still keeping an editable line. Placeholder and typed text are aligned the same way.

Tap + to get a compact icon list: Camera, Gallery, Files, Location, and Permissions. The Permissions row reports the current access mode. The top-right Chat actions (⋮) menu holds the live Context usage ring. Pick Context to see context usage, tokens from the latest run, and the cost breakdown. Reading usage needs no permission to modify session settings. When no cost breakdown exists, a reported model-call total is still displayed. Usage that is missing appears as unknown. Tap the model name and a compact menu opens above the composer, where you can search by model name, ID, or provider and expand provider groups. Search handles multiple terms and small typos in words of four letters or more, including adjacent letters swapped. All terms must match; short terms and version numbers get no typo correction. Within each provider, exact matches come first, and provider groups are ordered by their best match. Clearing the search brings back the usual order and leaves your selection untouched. No settings buttons appear in the picker. The default configured on the Gateway is marked on its model row. Picking a named model pins it to the session; Default model is a separate action that clears the override so the Gateway's current default applies again. Pinned and recent models stay reachable. Long model names are shortened with a middle ellipsis, and the full name is shown in the picker. The effort dial opens its slider and Fast mode without expanding the composer. While you drag the slider, the dial previews the effort; letting go applies it.

When the draft is empty and nothing is running, the trailing button starts Talk. As soon as you type, it becomes Send; if a run is active and the draft is empty, it shows Stop. During Talk, a live waveform takes the microphone's place and stays tappable so you can end Talk. When a run is active at the same time, a separate Stop button with a soft tint remains at the trailing edge for aborting that run.

To chat, open Home from the sidebar's Pages menu, or pick an existing session in the sidebar:

  • History: the Gateway normalizes chat.history for display. Inline directive tags, plain-text tool-call XML payloads (<tool_call>, <function_call>, <tool_calls>, <function_calls>, and truncated variants), and leaked ASCII or full-width model control tokens all get stripped. Stored assistant visibility follows display, phase, and final-source facts first, then drops raw assistant text that trims down to uppercase NO_REPLY; lowercase and wrapped forms stay visible. User text is never treated as silence. Oversized rows may be swapped for placeholders.
  • Long replies: on a capped assistant reply, tap View all to pull the full formatted text inline. Attachments remain in the conversation, and message actions act on the expanded text. To restore the preview, tap Show less or press Back; reopening reuses the reply already loaded. Loading states, retryable failures, unavailable messages, and required reconnects or Gateway updates show up inside the message rather than in an alert. Synthetic message-tool and commentary previews keep their current display and actions but offer no View all, since the copied transcript ID cannot retrieve that synthesized text. The older capped-preview format from released Gateways such as v2026.7.1-2 is recognized too. Android asks for up to 1,000,000 characters per text field, which matches the Gateway's default retrieval limit; results that are oversized or still capped show The full message is too large to display. instead of an incomplete reply.
  • Large code blocks scroll inside a bounded viewport, with Start of code, End of code, and Copy code controls. Start and End also bring that end of the block into view in the conversation. Selection is confined to the displayed text segment; Copy code copies the whole block. A separate Select text message action opens a plain-text selection reader; long answers are split into bounded pages, and selection applies to the page on screen.
  • Reading: automatic following pauses when you scroll up or use View all, Start of code, or End of code. Your reading position survives incoming content and window-size changes, and text or images are moved into view when space shrinks. If an idle conversation is resized so all content fits, following resumes. Jump to latest in the chat header resumes following; it shows only while newer content sits below the visible history and never covers messages.
  • Mermaid code blocks render as diagrams once the closing fence arrives or the reply finishes. Tapping a diagram opens a full-screen view with pinch-to-zoom and panning. The small corner controls copy the source or open a menu for switching between diagram and source. Rendering works offline with bundled assets. Diagrams that fail keep their readable source, and temporary failures offer retry. Code blocks in other languages stay code.
  • Thread activity: sidebar rows and search results use the activity each thread reports itself. A run that is inactive does not keep a working or queued indicator just because its last status was running or queued.
  • Session selection: while the app runs, every Gateway and agent remembers the last chat you explicitly selected. When you return to an agent, an older chat outside the recent page is checked directly; a temporary lookup failure shows an error without discarding that choice.
  • Archiving the open session returns you to the app's main chat only if that same session is still selected. If you switch sessions, agents, or Gateways while the archive finishes, your newer selection is preserved. A successful archive also clears the archived chat's remembered selection even when its push notification is missed.
  • New in the sidebar creates and selects an independent chat for the selected agent without clearing the previous session. It keeps the existing model/provider, thinking, and Fast Mode inheritance behavior, but appears separately in Threads rather than beneath the previous chat or Home. Existing ordinary New chats also appear independently even when an older app recorded the previous chat as their parent; their history and stored settings are unchanged. Forks, subagents, explicit worktree starts, and sessions without creation metadata keep their nesting. The sidebar and chat header show progress during creation and initial loading, and duplicate New actions are disabled. History refreshes do not cancel creation; if you select another session, agent, or Gateway while it finishes, that newer selection is preserved.
  • Offline history: cached transcripts update in the order live histories are accepted, so a delayed reconnect health check cannot bring back an older snapshot. When you switch sessions, queued cache updates for the session you left are preserved.
  • Refresh chat in chat actions reloads history and rechecks Gateway health without clearing pending messages. Chat readiness is distinct from the Gateway connection: an empty connected thread shows Chat not ready while health is unconfirmed or a check has failed. Use Refresh chat to check again; Gateway offline means the Gateway is disconnected. History failures do not stop later health checks. Once Android sees a recovered run finish, a delayed history response does not restore that run's Stop button or partial reply.
  • Send: chat.send. Outside an active Talk session, you can send text or staged attachments while the agent is working. A new draft brings Send back; clearing it restores Stop. The Gateway applies the existing queue mode, so steering does not require stopping the current run. Sending stays disabled while another submission, attachment staging, or microphone capture owns the draft.
  • Queued message controls: Delete removes the local queued copy, including while a reconnect refresh is still finishing. It does not undo a message the Gateway already accepted; use Stop to cancel an active turn.
  • Durable sending: every send (text, picked images, and voice notes) is journaled to a per-gateway on-device outbox before any network attempt, so app termination cannot lose submitted input. Sends queued while offline deliver in order on reconnect with stable request keys that prevent duplicate sends, and a send is retired only after the turn is visible in saved chat.history; an acknowledgement alone is not treated as proof of delivery. Acknowledged reconnect sends show the same streaming progress as online sends; requests that never reach the socket queue remain queued for the next connection. Ambiguous outcomes (lost acknowledgement, app killed mid-send, Gateway restart before the transcript write) surface as visible rows with explicit Retry/Delete instead of auto-resending. If refreshed history changes branches, earlier queued input keeps its text and attachments but requires explicit retry; input admitted after that history is displayed can send normally when reconnecting to the same branch. Slash commands never auto-replay across a reconnect; they park for explicit retry. The queue is bounded (50 messages and 48 MB of attachment bytes per Gateway) and unsent rows expire after 48 hours. Composer drafts that were never submitted are not process-durable.
  • Completed answers show up to eight compact source cards for cited pages found in that run’s successful web searches and fetches. Tap a card to read its recorded search snippet or page excerpt and open the source. The cards do not fetch page content; favicons come through the Gateway and honor gateway.controlUi.automaticallyFetchFavicons, with a globe when disabled or unavailable.
  • Image input works through the picker and Android Sharesheet. Sent photos sit above your text bubble; adjacent photos wrap into compact rows. Assistant photos stay beside their associated text in message order. Tap a photo for the full-screen preview. Messages display at most four image previews at once; Next images and Previous images reach the rest without keeping every decoded image in memory. Assistant-generated images resolve through the paired Gateway connection and retain only their small artifact references in the offline transcript cache. Downloads are capped at 12 MiB and decoded to bounded display bitmaps.
  • Push updates (best-effort): chat.subscribe -> event:"chat"
  • Listen: long-press an assistant message and choose Listen to hear it; audio renders via Gateway tts.speak with the configured TTS provider chain, and on-device system TTS is used when the Gateway cannot render audio. Playback stops on session switch, new chat, app backgrounding, or chat close.

Reactions

Emoji reaction chips appear on saved prompts and assistant replies, showing counts and the names of who reacted, with your own reactions highlighted. To toggle a reaction, tap its chip. Alternatively, long-press any message (a media-only message works too) and pick Add reaction. The quick palette is the same one the Control UI offers; More… takes a single emoji, joined emoji and flags included. Available controls depend on the Gateway's operator and session-sharing permissions, and read-only viewers can still see reactions. Updates arrive live while the conversation is open and generate no notifications. See Reactions.

Agent browser in chat

Whenever the Browser plugin reports an identifiable tab, Chat displays a preview of the session's most recent browser tab under Agent browser. Tapping the upward chevron lets you interact without leaving the conversation, and your draft stays intact. The downward chevron or Android Back takes you back to the preview. Collapsing hides the browser's keyboard but leaves your chat draft untouched. Open in your browser is a distinct, explicit action. Website links and Desktop behave as they always have.

The close icon takes the card out of chat without shutting the agent's remote tab. To bring it back, pick Chat actions > Agent browser. Refreshing the same browser result will not reopen a dismissed card; only a new browser-tool presentation can display it again. Closing works even when the browser is offline or unavailable.

The preview is tied to the connected Gateway and to the exact browser profile, host or node, and tab named in the tool result. It never launches a second browser or swaps in a different tab. Changing sessions or Gateways swaps the viewer; losing the connection strips its controls until the connection comes back. A remote tab that is stopped or closed stays unavailable instead of being replaced.

This relies on the Gateway's existing Browser panel plus the operator.admin browser permission. The connected Gateway has to advertise browser-focus support and run its bundled Control UI. Older Gateways, a disabled Control UI, and custom UI roots display an unavailable notice rather than loading an unsupported page; to get embedded control, update the Gateway and use its bundled UI. The card can still be closed. Nothing here creates an extra browser service or session-sharing permission.

7. Camera

Camera commands (foreground only; permission-gated): camera.snap (jpg), camera.clip (mp4). For parameters and CLI helpers, see Camera node.

8. Voice + expanded Android command surface

  • Reach them via the sidebar's Pages menu. Voice input lives in the Chat composer; there is no dedicated Voice tab.
  • Tapping the composer microphone runs on-device speech recognition and inserts the transcript into your draft. A Stop icon replaces the microphone while listening; tap it to end listening. During startup or transcription, a Close icon cancels that attempt. Long-pressing the microphone opens Voice options, where Record voice note creates an attachment. Rather than dropping an attempt silently, the UI reports unavailable recognition, missing permission, busy/network failures, and no-speech outcomes. When dictation is unavailable and a Gateway is selected, Record voice note offers a fresh recording while preserving the draft. It does not salvage speech from the failed dictation attempt, and it never sends anything automatically.
  • To begin continuous Talk, tap the trailing Talk button when the draft is empty and no run is active. The microphone menu offers only dictation and voice notes. Dictation, voice-note recording, and Talk are mutually exclusive microphone paths.
  • Your chosen agent remains bound to Talk and the main chat when the same Gateway reconnects, even while its agent list refreshes. If that agent is removed, the app falls back to the Gateway default when your role permits, otherwise to the first available agent. Switching Gateways or restarting the app clears this in-memory choice and waits for the allowed agent list before starting Chat. When the list is empty, No agents available for this role appears. If discovery fails, retry the Gateway connection to initialize Chat.
  • Before capture begins, Talk Mode promotes the existing foreground service from connectedDevice to connectedDevice|microphone, then demotes it once Talk Mode stops. The node service declares FOREGROUND_SERVICE_CONNECTED_DEVICE with CHANGE_NETWORK_STATE; on Android 14+ the FOREGROUND_SERVICE_MICROPHONE declaration, the RECORD_AUDIO runtime grant, and the microphone service type at runtime are also required.
  • By default, Android Talk relies on native speech recognition, Gateway chat, and talk.speak via the configured Gateway Talk provider. It inherits the session's thinking setting. Local system TTS is used only when talk.speak is unavailable.
  • Changes to Gateway config refresh Android's cached Talk settings the next time they are used, with no reconnect and no interruption to an active capture.
  • Android Talk uses the realtime Gateway relay only when talk.realtime.mode is realtime and talk.realtime.transport is gateway-relay.
  • Phone relay Talk keeps accepted agent work intact when Talk fails, when the app goes to the background, or when the voice mode changes. The answer still shows up in chat; an explicit Stop cancels it. This needs a Gateway that advertises talk-session-close-disposition; older Gateways and Wear Talk keep the aborting close behavior.
  • Turn on Settings → Voice → Listen for wake words to use foreground on-device Voice Wake. Android advertises voiceWake only when it is enabled, on-device recognition and microphone permission are available, and wake words are synchronized with the current Gateway.
  • Other Android command families (availability depends on device, permissions, and user settings):
    • device.status, device.info, device.permissions, device.health
    • device.apps only when Settings → Phone Capabilities → Installed Apps is enabled; by default it lists launcher-visible apps (pass includeNonLaunchable for the full list).
    • notifications.list, notifications.actions (see Notification forwarding below)
    • photos.latest
    • contacts.search, contacts.add
    • calendar.events, calendar.add
    • callLog.search
    • sms.search
    • motion.activity, motion.pedometer

9. Workspace files (read-only)

The Files card lives in Overview, reachable from the sidebar's Pages menu. It browses the active agent's workspace via the read-only agents.workspace.list / agents.workspace.get Gateway RPCs: drilling into directories, previewing text and images, and exporting through the Android share sheet. No write operations exist, and the Gateway caps preview sizes.

Should the app fail to prepare a file or open the share sheet, Could not share file appears and the preview stays open so you can retry or go back.

Review command approvals

Pending exec requests can be reviewed under Settings -> Approvals by an operator connection holding operator.admin, or by a paired operator.approvals connection that the Gateway explicitly targets. Before enabling its buttons, the app loads the Gateway's sanitized approval record, displays any security warning and the exact decisions that request offers, and sends the approval ID and owner kind back to the Gateway.

Approval state is shared with the Control UI and supported chat surfaces. Whichever answer commits first wins; Android shows that saved result even if another surface replied first. When a resolve response is lost or the Gateway disconnects, the app keeps the action locked and re-reads the approval before offering another decision.

Gateways older than the unified approval methods fall back to the shipped exec-specific methods. Pending review still functions, but retained terminal state and the richer cross-surface result need an updated Gateway.

Answer agent questions

For operator connections with operator.questions (or operator.admin), Chat renders pending Gateway questions as native cards. Cards handle single- and multi-select options, option descriptions, free-text Other answers, and an expiry countdown. Reconnecting reloads pending questions from the Gateway. A card locks once this device answers it, another surface answers first, or the question expires or is cancelled.

Secret answer fields mask typed or pasted values and request password input with autocorrection off. Android submits secret answers without trimming leading or trailing whitespace.

Assistant entrypoints

Launching OpenClaw from the system assistant trigger (Google Assistant) works on Android. Holding the home button (or using another ACTION_ASSIST trigger) opens the app; saying "Hey Google, ask OpenClaw <prompt>" matches the app's declared App Actions query pattern and passes the prompt into the chat composer without sending it automatically.

The app manifest declares Android App Actions (shortcuts.xml capability), which is how this works. Nothing needs to be configured on the gateway side: the Android app handles the assistant intent on its own.

Note

Whether App Actions are available depends on the device, the Google Play Services version, and whether OpenClaw has been set as the user's default assistant app.

Notification forwarding

Device notifications can be forwarded by Android to the Gateway as node.event items. Configuration happens on the device, inside the app's Settings sheet, rather than in Gateway/openclaw.json config.

SettingDescription
Forward Notification EventsMaster toggle. Off by default; requires Notification Listener Access to be granted first.
Package FilterAllowlist (only listed package IDs forwarded) or Blocklist (default: all packages except listed IDs). OpenClaw's own package is always excluded in Blocklist mode to prevent forwarding loops.
Quiet HoursLocal HH:mm start/end window that suppresses forwarding. Disabled by default; defaults to 22:00-07:00 once enabled.
Max Events / MinutePer-device rate limit on forwarded notifications. Default 20.
Route Session KeyOptional. Pins forwarded notification events into a specific session instead of the device's default notification route.

Note

The Android Notification Listener permission is required for notification forwarding. Setup includes a prompt from the app asking for it.

Notifications from WhatsApp, WhatsApp Business, Telegram, Telegram X, Discord, and Signal are never forwarded. Native OpenClaw channel sessions already own those messages, so sending the Android notification onward as a separate node event might deliver a reply into the wrong conversation.

7,718 words · updated Oct 26, 2026