Skip to main content

Peer-to-peer clipboard sync over Syncthing.

Project description

ClipSync

Peer-to-peer clipboard sync for Windows, macOS, and Linux. Copy on one machine, paste on another. No account, no cloud, no central server. The data never leaves your devices.

Verified working across Windows, macOS, and Linux, across different networks.

Why this exists

Every other cross-platform clipboard tool I found falls into one of three buckets:

  1. Same-LAN only - needs mDNS or a discovery broadcast, so it breaks the moment you're on a different network (or a corporate one that blocks multicast).
  2. Needs a signaling server - even the "peer-to-peer" modes usually still need a relay or a server you host somewhere, which means one more thing to maintain and one more thing that can go down.
  3. Reinvented the networking stack - custom libp2p, custom NAT traversal, custom encryption. Which means custom bugs.

The design choice here is to reuse Syncthing instead of inventing anything. Syncthing has already solved peer discovery, NAT traversal, TLS with forward secrecy, and relay fallback for millions of users. By treating a single file (clipboard.txt) inside a shared Syncthing folder as the transport, you inherit all of that for free, including cross-WAN sync that just works, without Tailscale, without port forwarding, and without a VPN.

Two loops sit on top:

  • OUT polls the local clipboard and writes changes to the file.
  • IN watches the file with filesystem events and applies remote changes to the clipboard.

A shared-last-value guard prevents ping-pong when both sides see the same write. Newlines are normalized to LF so Windows CRLF doesn't look like a real change and retrigger sync.

At-rest encryption

Syncthing already encrypts data in transit. For defense-in-depth, in case someone gains read access to the sync folder on one device, you can set a passphrase in Settings. Payloads are then encrypted with Fernet (AES-128-CBC + HMAC-SHA256) using a PBKDF2-SHA256 key derivation, and prefixed with a CSENC magic header so peers can detect ciphertext and refuse to paste it raw.

Every device in the group needs the same passphrase. A mismatch logs a clear "decrypt failed (passphrase mismatch?)" message rather than silently pasting ciphertext.

Install

pip install offbyonebit-clipsync
clipsync

Note: the PyPI package name is offbyonebit-clipsync (the name clipsync was already taken).

Or run from source:

pip install -r requirements.txt
python -m clipsync

Python 3.11+. The correct Syncthing binary for your platform is downloaded on first run from the official Syncthing GitHub release.

Linux setup notes

pystray picks its tray backend at import time: PyGObject + AppIndicator if available, XEmbed otherwise. KDE Plasma and several other modern desktops no longer render XEmbed icons; they only speak StatusNotifierItem, which AppIndicator provides. If the tray icon silently never appears, install the system packages and make them visible to your venv.

Debian / Ubuntu / Mint

sudo apt install python3-gi gir1.2-ayatanaappindicator3-0.1 xclip

Fedora

sudo dnf install python3-gobject libayatana-appindicator-gtk3 xclip

Arch

sudo pacman -S python-gobject libayatana-appindicator xclip

If you use a virtualenv, set include-system-site-packages = true in its pyvenv.cfg so the system-installed PyGObject is importable. xclip is the X11 backend pyperclip uses for clipboard access; on Wayland install wl-clipboard instead. GNOME users typically also need the AppIndicator extension for the icon to actually show up.

Pairing

  1. Tray icon -> Add Device.
  2. On the second machine, do the same.
  3. Scan the QR code with the webcam, or paste the device ID shown below it.
  4. Both sides auto-accept and start syncing.

Settings

  • Start on login (HKCU Run on Windows, LaunchAgent on macOS, XDG autostart on Linux).
  • Show notifications.
  • Pause sync.
  • Sync folder path.
  • Encryption passphrase.
  • View Syncthing logs.
  • Reset / unpair all devices.
  • Check for updates (compares against the latest GitHub release and opens the download page, no auto-install, no phone-home on startup).

Settings changes from the UI take effect immediately; hand-editing settings.json is also picked up, the file is watched for changes.

How it compares

Tool Cross-WAN No signaling server E2E encrypted Tray UI
ClipSync yes (via Syncthing relays) yes yes yes
p2p-clipboard partial yes yes yes
ClipCascade yes no (self-host required) yes yes
cross-clipboard no (LAN mDNS) yes yes no
macOS Universal Clipboard yes (iCloud) no N/A built-in
Windows Cloud Clipboard yes no (Microsoft account) N/A built-in

Project layout

Module Purpose
config.py Paths, settings with on-disk watch, logging.
syncthing.py Binary download, config generation, REST API client, subprocess lifecycle.
clipboard.py OUT poll + IN watcher, loop guard, optional Fernet encryption.
pairing.py QR generation, webcam scan, auto-accept of pending devices.
ui.py CustomTkinter windows for pairing, devices, and settings.
autostart.py Cross-platform "run at login" toggle.
main.py Tray icon, orchestration, shutdown ordering.

Status

Fully tested and working on Windows, macOS, and Linux.

License

MIT. See LICENSE. You can fork, modify, and redistribute (including commercially), but the copyright notice must travel with the code.

Support

This project is free and I don't ask for anything. If it's useful to you, a star on the repo is appreciated, and if you want to follow along with other things I'm building, you can find them under @offbyonebit.

If you'd like to support development, you can sponsor me on GitHub.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

offbyonebit_clipsync-1.0.0.tar.gz (78.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

offbyonebit_clipsync-1.0.0-py3-none-any.whl (64.7 kB view details)

Uploaded Python 3

File details

Details for the file offbyonebit_clipsync-1.0.0.tar.gz.

File metadata

  • Download URL: offbyonebit_clipsync-1.0.0.tar.gz
  • Upload date:
  • Size: 78.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Linux Mint","version":"22.3","id":"zena","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for offbyonebit_clipsync-1.0.0.tar.gz
Algorithm Hash digest
SHA256 75885eca784475fad5b4195337f73ae6526a8003ccf3e8ff14552c85f3d46abd
MD5 36ee7a2ce2a5729592b13856dac196dc
BLAKE2b-256 f47dfa0a36a2a33a8b0240d83bcf338b71484dc8eb5c4107fa1d8bcee9459bef

See more details on using hashes here.

File details

Details for the file offbyonebit_clipsync-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: offbyonebit_clipsync-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 64.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Linux Mint","version":"22.3","id":"zena","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for offbyonebit_clipsync-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d0dc5367cd0142451289ea21801c1a9f00d48b4f03775cd5f08d92a835a83376
MD5 c4c8fff6dd64c547ba83735ea757c67b
BLAKE2b-256 28c2da3a0afdf0f75329bf40a15cc1cc623b0598006bd71bc1aead470239e718

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page