Connect your Android phone to macOS or Windows over wireless ADB.
Pair once. Connect wirelessly. Deploy effortlessly.
Website · Download · Setup guide · Contributing
English · Türkçe · Deutsch · Español · Français · Português (Brasil) · 简体中文 · 日本語
Support the project
Buy Me a Coffee ·
thanks.dev
| Android · Connected | Android · Pairing | macOS · QR code & token |
|---|---|---|
![]() |
![]() |
![]() |
Release 1.0.0: macOS, Windows, Android.
| Piece | Folder |
|---|---|
| Android | android/ |
| macOS and Windows | mac/ |
| Web | web/ |
cd web && npm install && npm start
cd mac && npm install && npm start
cd android && ./gradlew :app:assembleDebugPairspan has two halves: the desktop app (macOS or Windows) and the Android app. Both talk to the gateway at https://pairspan.ferhatozcelik.com, so the phone and the computer do not need to be on the same network. One desktop can host several phones at once.
macOS
- Download
pairspan-mac-1.0.0.dmgfrom the release page and drag Pairspan into Applications. - The build is not notarized. If macOS blocks the first launch, right-click Pairspan and choose Open.
- Pairspan lives in the menu bar. Click its icon to see the pairing token and QR code.
adbis bundled, nothing else to install.
Windows
- Download
pairspan-windows-1.0.0.exefrom the same release page and run it. - The installer is not code-signed. If SmartScreen warns, choose More info, then Run anyway.
- Pairspan lives in the system tray. Click its icon to see the pairing token and QR code.
adb.exeis bundled, nothing else to install.
Use the switch in the window header (or Enabled in the tray menu) to turn Pairspan on or off. While it is off, no phone can connect.
- Download the APK from the release page and install it (allow installs from your browser or file manager when asked). Android 8.0 or newer is required, and Android 11 or newer for wireless debugging.
- Open Pairspan and allow notifications and the camera when asked. The camera is only used to scan the QR code.
- On the phone, open Settings → About phone, tap Build number seven times, then open Developer options and turn on USB debugging. Turn on Wireless debugging too if your phone has it.
Pairspan can switch on its own accessibility and notification services and wireless ADB without sending you through Settings. Android only allows that after WRITE_SECURE_SETTINGS is granted from a computer. The desktop app does it for you:
- Connect the phone to the computer with a USB cable, with USB debugging on, and Pairspan installed on the phone.
- In the desktop window, find One-time phone permission and click Find USB phones.
- If the phone shows an "Allow USB debugging?" prompt, accept it and scan again.
- Click Grant permission under your phone. The app runs this for you, using its bundled
adb, and then switches the phone's ADB to port 5555 so Pairspan can reach it without a cable:
adb shell pm grant com.pairspan android.permission.WRITE_SECURE_SETTINGS
adb tcpip 5555- On the phone, tap Allow on the "Allow USB debugging?" prompt and tick Always allow. You do not have to type any command.
Notes:
- The permission lasts until Pairspan is uninstalled. The port 5555 step lasts until the phone restarts; click Grant permission again after a restart.
- If it fails with a security exception, enable USB debugging (Security settings) in Developer options (some Xiaomi/Redmi/POCO phones) and try again.
- You can also run the command yourself with any
adb. The Android app shows it under Getting ready → System access with a Copy command button. - For phones without Wireless debugging, run
adb tcpip 5555once over USB. Pairspan will use that port.
- Make sure the desktop app is enabled and shows Connected to the Pairspan service.
- In the Android app tap Scan QR code and scan the code from the desktop, or type the pairing token.
- The phone appears under Connected devices on the desktop with its Device ID and the desktop's Client ID. The same two ids are in the Android app under Settings.
- To add another phone, repeat this pairing step with the new code (a used code is replaced right away).
The desktop app and the Android app never open ADB to each other. Both connect to the gateway in web/. The public site is https://pairspan.ferhatozcelik.com. To run your own, start that process and build both apps with the same URL and token.
- Node.js 22, or Docker
- A hostname with TLS if the gateway is reachable from the internet. Clients use
https://and the WebSocketwss://…/ws - One
GATEWAY_TOKENshared by the server, the desktop app, and the Android app
Sessions stay in memory. Restarting the process drops them. The gateway does not run adb. The desktop app does, on 127.0.0.1 only.
web/.env.example, mac/.env.example, and android/.env.example use the same two lines. Set the public URL to the address phones and computers can open. Leave the token empty in git.
GATEWAY_PUBLIC_URL=https://pairspan.example.com
GATEWAY_TOKEN=
GATEWAY_PUBLIC_URL is written into pairing QR codes. GATEWAY_TOKEN is sent on every hello. If the server token is empty, anyone who can open /ws can join. Set a long random token before the process is reachable from the internet.
openssl rand -hex 32Do not commit the token. Put it in the environment of the process you run, or in web/temp.env for Docker. temp.env is not part of the repo.
cd web
npm install
export GATEWAY_PUBLIC_URL=https://pairspan.example.com
export GATEWAY_TOKEN='paste-the-token'
npm startThe process listens on 0.0.0.0:3000. It serves the landing page, /p/, WebSocket /ws, and GET /health.
curl -fsS http://127.0.0.1:3000/healthA healthy process returns {"ok":true,"service":"pairspan",...}.
From web/:
docker build -t pairspan:latest .Write web/temp.env:
NODE_ENV=production
GATEWAY_PUBLIC_URL=https://pairspan.example.com
GATEWAY_TOKEN=paste-the-token
web/docker-compose.yml reads that file and publishes 127.0.0.1:16200 to container port 3000.
docker compose up -d
curl -fsS http://127.0.0.1:16200/healthPut a TLS reverse proxy in front of 127.0.0.1:16200. Forward WebSocket upgrades on /ws. Check the public URL the same way:
curl -fsS https://pairspan.example.com/healthWrite the same URL and token into mac/.env.example and android/.env.example, then rebuild. The desktop app reads .env.example at launch. The Android app copies both values into the APK at compile time.
cd mac && npm install && npm start
cd android && ./gradlew :app:assembleDebugA client built with a different token is rejected. The desktop window should say Connected to the Pairspan service before you scan the QR code. Then follow Pair above.
Each phone gets its own local port on the computer, starting at 127.0.0.1:44755 and going up. The desktop window lists the adb connect target for every phone.
adb devices
adb -s 127.0.0.1:44755 shell idIf adb devices shows a phone as authorizing, unlock it and accept the "Allow USB debugging?" prompt, then tick Always allow.
To disconnect a phone, tap Remove connection in the Android app. To disconnect everything, turn the desktop switch off.
Use Pairspan only with devices you own or have explicit permission to access, for legitimate development, debugging and device management. Do not use ADB for unauthorized access, covert monitoring, data theft, malware or bypassing security controls.
In the USB setup described above, the device owner must enable USB debugging, unlock the phone and approve Android’s debugging authorization prompt. Only approve computers you trust. Pairing or automatic reconnection must respect this authorization and must not override revoked permissions. See Android’s ADB documentation.
Keep pairing tokens and ADB keys private. To end access, remove the Pairspan connection and revoke USB debugging authorizations in Android’s Developer options; disable debugging when no longer needed. Follow Android’s security and permission model and the applicable Google Play Device and Network Abuse policy. USB authorization alone does not establish Google Play policy compliance.


