Mobile sync
How to sync clipboard between desktop and an iPhone or any SyncClipboard-compatible client — on the LAN, or across networks via a server node or Tailscale.
Mobile sync is an HTTP companion mode (introduced in 0.7): the desktop daemon exposes a small SyncClipboard-compatible HTTP service, and a paired phone reads / pushes clips to it with HTTP Basic Auth.
It is intentionally narrower than desktop ↔ desktop sync:
- Not P2P. The phone is a plain HTTP client — no NAT punching, no relay. It works on your LAN out of the box; for cross-network reach, run a headless server node (a public HTTPS endpoint) or use a Tailscale / VPN overlay (see below).
- Plain HTTP + Basic Auth at the listener — TLS is added by a reverse proxy or the overlay tunnel, not the listener itself. On a bare LAN, only enable on networks you trust.
- Phone is not a peer of the space — it doesn't get a node ID and doesn't see the encrypted history database.
Two phones don't sync with each other; they each talk to the desktop.
v1 wire format is unencrypted HTTP on the LAN. Don't enable the listener on coffee-shop Wi-Fi, conference Wi-Fi, or any network where you don't trust everyone on the same SSID.
Enable mobile sync (one-shot)
The fastest way is the wizard — flip the feature on, configure the LAN listener, register the phone, and print a QR code in one go.
Open the Devices page
The page has a "This device" Hero on top and a row of two tabs:
Paired devices and Mobile sync. Switch to the Mobile sync
tab; two action buttons appear on the right of the tab bar:
Configure and Add device. If the listener fails to bind,
Add device stays clickable and clicking it surfaces the reason as a
toast — the full detail is inside the Configure modal.
Click Configure
A centered "Mobile sync settings" dialog opens. Under Sync switches, turn on Enable mobile sync and LAN listener. Then under Network parameters:
- Bind IP — leave on
Autoto have the desktop offer every RFC1918 candidate at copy time, or pick a specific interface to fix the advertised URL to one address. Tailscale CGNAT addresses (100.64.0.0/10) are included in the dropdown so a Tailscale- reachable phone can be paired the same way as a LAN phone; this is independent of the Settings → Network → Allow overlay network addrs toggle, which only affects desktop ↔ desktop pairing. Either way the actual socket always binds to0.0.0.0; this picker only controls which address gets advertised to the mobile device. - Port — defaults to
42720. Change only if there's a conflict.
The dialog shows the current listening address as you go. If
Bind IP is Auto, that row expands inline into every candidate LAN
IPv4 — copy the one the mobile device can dial. If a specific
interface is picked, a single URL is shown. The LAN listener is
hot-swapped: changes apply immediately, no daemon restart needed.
If the daemon raises lan_listener_error (port in use, permission
denied, etc.), a red Alert at the top of the dialog spells out the
reason; clicking Add device surfaces the same reason as a toast
while the listener can't bind.
Click Add device
Pick a label (e.g. "My iPhone 15"). The desktop mints a one-time username and password and shows them inside a single scan-first credentials modal:
- Big QR (top, always on) — encodes every reachable candidate
address (the public entry if configured, plus all qualifying
interface IPs including Tailscale CGNAT) together with the
credentials as a single
uniclipboard://connectURI, so one code works whether the phone is on the LAN or coming in from outside; clients that understand the candidate list probe them in order. Scan it from the UniClipboard iOS App (TestFlight public beta — recommended; see Pair an iPhone below), the UniClipboard Android client, or any other SyncClipboard-protocol client. All fields auto-fill; no typing. A baseUrl dropdown sits next to the QR so you can switch which address is the preferred (first) candidate — the remaining candidates stay in the code — without re-opening the Configure modal. - "Haven't installed a client?" disclosure (collapsed by default) — expand it when the phone has no client yet. Inside are two tabs: iOS shows a QR for the TestFlight invite (with a Shortcut install QR as a sub-fallback for users who can't or won't use TestFlight), and Android shows a QR for the GitHub Releases APK download page.
- "Credentials" disclosure (amber, collapsed by default) —
expand it to reveal the raw
username/passwordfor clients that need manual entry. A Backup button copies aServer / Username / Passwordblock to the clipboard in one go.
Closing the modal (the Done button, the X icon, Esc, or
clicking outside the dialog) all keep the device — there's no
in-modal discard path. To revoke a device, open it from the
Mobile sync device grid instead (see
Manage paired devices).
The plaintext password is shown once. The desktop only retains an Argon2id hash after the modal closes.
# One-shot: enable feature + LAN listener, register one device,
# print install QR + a one-time password.
uniclip stop # required: writes refuse a running daemon
uniclip mobile setup # interactive (recommended)
# Or non-interactive (e.g. CI / scripts)
uniclip mobile setup \
--label "My iPhone 15" \
--accept-network-risk \
--non-interactive
# → prints baseUrl, username, password (one-time), installUrl, and a
# multi-address QR (ASCII) that the phone probes address-by-address
uniclip start # bring the daemon back upFor non-interactive runs, --label and --accept-network-risk are
required. --ip / --port are optional advanced pins — omit them and the
QR carries every detected interface, so there is normally nothing to pick.
--username / --password-stdin are optional and default to auto-mint.
The plaintext password is shown once. If the user loses it,
click the device card on the Mobile sync grid, press
Edit device inside the dialog and set or regenerate the password
(or uniclip mobile revoke <id> + add) — there
is no way to retrieve the original.
Pair an iPhone
There are two iOS options. The UniClipboard iOS App is the recommended path; the Shortcut stays as a fallback.
iOS (UniClipboard App — TestFlight public beta)
The UniClipboard iOS App is currently distributed through TestFlight as a public beta. Invite link:
https://testflight.apple.com/join/nyNQ8dQe
Install TestFlight from the App Store
On your iPhone, open the App Store, search for TestFlight, and install it. TestFlight is Apple's official beta-distribution app and is required to install the UniClipboard beta build.
Open the invite link
On the iPhone, open the TestFlight invite link:
https://testflight.apple.com/join/nyNQ8dQeiOS will hand the link off to the TestFlight app. Tap Accept, then Install, and UniClipboard will be added to the Home Screen.
Generate credentials on the desktop Add device
Back on the desktop, follow the flow above to click Add device under Devices → Mobile sync. The credentials modal opens directly on the connect-URI QR — base URL, username, and one-time password are encoded into a single scan. (If you haven't installed the App yet, expand the "Haven't installed a client?" disclosure for a TestFlight QR; otherwise just scan the big QR from the App right away.)
Enter the connection info in the App
Open the UniClipboard iOS App, tap Add server, and scan the big QR from the desktop credentials modal. The base URL, username, and password are filled in automatically; just confirm and save. Once connected, the iPhone syncs clipboard with the desktop in both directions.
If the install or first launch hangs, turn off your proxy / VPN client first. Some users on Loon, Surge, Shadowrocket, Clash, or similar tools see one of these symptoms:
- TestFlight shows a certificate or HTTPS error when opening the invite link, or
- TestFlight can't reach App Store Connect and the Install button spins forever.
Temporarily disable the proxy (global rules, TUN mode, HTTPS decryption / MitM included) so TestFlight goes direct. Re-enable it once the App is installed — the App itself only talks to your desktop over the local network and doesn't depend on the proxy.
iOS (Shortcut — fallback, no UniClipboard App)
If TestFlight isn't an option right now, the Shortcut path still works. In the credentials modal, expand the "Haven't installed a client?" disclosure, stay on the iOS tab, and look for the "Don't want the App? Scan to install the Shortcut as fallback" sub-QR.
- Scan the Shortcut install QR with the iPhone Camera (or open the
install link in Safari). iOS prompts to install
UniClipboard.shortcut. - Open the installed Shortcut and manually paste the base URL, username, and password (from the Credentials amber disclosure at the bottom of the modal — use its Backup button to copy all three in one go) into the Shortcut's matching fields. The Shortcut QR only carries the install link — it does not prefill credentials.
- Run the Shortcut (or trigger it from the iOS share sheet) to
Android / other clients
The UniClipboard Android client lives at github.com/UniClipboard/UniClip — one client for both iOS and Android, with Android APKs published in releases (side-load only, no Google Play). Because the desktop listener speaks the SyncClipboard protocol, any other SyncClipboard-compatible client also works. Recommended picks today:
- UniClipboard/UniClip — our official app (the same client as on iOS): install the APK, enter the base URL, username, and password, and clipboard sync goes both ways. Recommended for most Android users.
- Upstream SyncClipboard — the protocol's reference implementation. Primarily a desktop client, but Android builds are published in its releases. A reasonable pick if you already live in the SyncClipboard ecosystem or want to track upstream directly.
Either way, the connection settings are the same:
- Base URL / server address —
http://<advertised-IP>:<port>(e.g.http://192.168.1.5:42720). Notehttp://, nothttps://— the listener itself has no TLS in v1. - Username — printed by the credentials modal /
setup. - Password — printed by the credentials modal /
setup(one-time).
Public access via an HTTPS reverse proxy. For deployments that expose mobile sync over the public internet (e.g. a headless server node), put a TLS reverse proxy such as Caddy or nginx in front of the plain-HTTP listener and advertise its address instead of an internal IP:
uniclip mobile network set \
--url https://clip.example.com \
--accept-network-riskThe install URL / QR then encodes https://clip.example.com (no
internal port), while the listener stays plain HTTP on the internal
network. The proxy terminates TLS and forwards to the internal
mobile_lan port, which must not be published directly to the
public internet. The --ip <IP> form instead produces the LAN
http://<IP>:<port> URL; the two are mutually exclusive.
The UniClipboard mobile app speaks the same SyncClipboard-compatible protocol as the desktop listener. Bugs in the app itself are usually best filed at UniClipboard/UniClip, while protocol-side bugs on the desktop listener belong here in the main repo.
Android limitations today. No TLS at the listener (plain HTTP + Basic Auth — TLS comes from a reverse proxy or overlay), same-LAN by default (cross-network via a server node or Tailscale), not a peer of your space's trust mesh, and Android 10+ background-clipboard restrictions can delay or gate writes when the app is not in the foreground.
Cross-network sync via Tailscale
Put the desktop and phone on the same Tailscale network (tailnet) and each gets
a 100.x.x.x address — the phone can reach the desktop from cellular or a
remote Wi-Fi exactly as if they shared a LAN, with no VPS and no domain. Since
0.12 the Bind IP dropdown also lists 100.64.0.0/10 (Tailscale's CGNAT
range).
For the full walkthrough, caveats, and troubleshooting see Cross-network sync with Tailscale. The other cross-network path is a self-hosted server node, which exposes the gateway as a public HTTPS endpoint; that page also compares the two.
This only changes reachability, not the v1 HTTP wire format. The listener still speaks plain
HTTP + Basic Auth; confidentiality is provided by the Tailscale / WireGuard tunnel you trust. It
also does not close the listener on your LAN — the socket always binds 0.0.0.0, and "Bind
IP" only picks which address is advertised to the phone.
Manage paired devices
| Action | GUI | CLI |
|---|---|---|
| List paired devices | Devices page → Mobile sync panel | uniclip mobile status |
| Add another device | Mobile sync panel → Add device | uniclip mobile add --label "…" |
| Edit a device | Click device card → dialog → Edit device (label / username / password) | GUI only today; mint a new one and re-pair the phone |
| Revoke a device | Click device card → dialog → Revoke | uniclip mobile revoke <device-id> |
| Disable feature | Configure dialog → switch off | uniclip mobile disable |
| Inspect listener URL | Mobile sync panel header | uniclip mobile status |
Editing lets you change the label, username, and/or password from the Edit device view. Setting or regenerating the password mints a fresh one-time password and atomically invalidates the previous Argon2id hash; changing the username reissues the password too. The old credentials stop working immediately, so update the phone (UniClipboard iOS App, Shortcut, or other client) with the new credentials.
Revoking removes the device record. Any subsequent request with
the old credentials gets 401 Unauthorized.
Disabling the feature turns the master switch and listener off
together but leaves paired-device records in place — re-enable
later and the same usernames continue to work. To wipe paired
records, use revoke (or the GUI revoke button) explicitly.
Security model — what's covered, what isn't
| Surface | Covered |
|---|---|
| On-disk password storage | Yes — only an Argon2id hash is persisted server-side. |
| Credential rotation | Yes — Rotate password mints a new one and invalidates the old hash. |
| LAN-side wire confidentiality | No (v1) — plain HTTP. TLS comes in v2. |
| Cross-network reachability | LAN by default — extend it with a server node (public HTTPS) or a Tailscale / VPN overlay (below). |
| Mobile-as-peer trust | No — phone never participates in the iroh / space trust mesh. |
Practical implications:
- Treat the LAN listener like an SSH server on a private network: be selective about where you turn it on.
- Public Wi-Fi: keep the listener disabled. Re-enable on a trusted network when you actually want the integration.
- Server node: for always-on, cross-network access from anywhere (without putting every device on a VPN), run a headless server node that fronts the gateway with a TLS reverse proxy — full steps in Self-hosting a headless server node.
- VPN / Tailscale: a VPN or Tailscale tailnet that puts both the
desktop and the phone on the same virtual subnet (RFC1918 or
Tailscale's
100.64.0.0/10) is a reasonable "LAN-style sync from outside the home" workaround — full steps in Cross-network sync via Tailscale. It's still plain HTTP on the wire; the VPN / WireGuard tunnel provides the confidentiality, so the overlay network itself must be trusted.
Troubleshooting
For the full checklist (phone can't open the URL, 401, broken
images, what to do after changing the LAN IP), see
Troubleshooting — Mobile sync (iOS Shortcut).
Where to look next
- Mobile LAN API — the wire protocol that the listener speaks (SyncClipboard-compatible HTTP + JSON).
- Mobile sync connect URI — the
uniclipboard://connectQR protocol. Read this if you're writing a new SyncClipboard-compatible client or shortcut that consumes the Scan to add QR. - CLI reference — Mobile sync — every
uniclip mobile ...subcommand and flag. - Self-hosting a headless server node — run the gateway on a public VPS so the phone reaches it over HTTPS from any network.
- Pairing & sync — Mobile companion — how mobile sync compares to desktop ↔ desktop pairing.
- Devices — Mobile sync devices — the panel layout and per-device row controls.