Excalidraw Live Sync

approvedunreviewed

by shenid

Co-edit Excalidraw drawings in real time with live cursors over a LAN or a virtual LAN such as Radmin VPN, Hamachi, ZeroTier or Tailscale.

Updated todayMIT

Excalidraw Live Sync

Русская версия

Live collaboration for the Excalidraw plugin in Obsidian: several people draw on the same board in real time and see each other's cursors and laser pointer.

There is no server: one participant hosts, the others connect to them directly over TCP. Any network where participants can reach each other's IP works:

  • a regular LAN or Wi‑Fi;
  • Radmin VPN (26.x.x.x addresses), Hamachi (25.x.x.x), ZeroTier, Tailscale;
  • any tunnel that forwards the host's TCP port.

Desktop only: mobile Obsidian has no Node.js networking API.

Network use

This plugin talks to the network — that is its whole purpose. To be explicit:

  • When you host, it opens a TCP server on the port from the settings (47321 by default) on all network interfaces of your computer, so participants on your LAN or VPN can connect.
  • When you join, it opens a TCP connection to the address you enter.
  • Only the participants of a session exchange data: drawing elements, embedded images and cursor positions of the drawing that is being shared. No other vault content is sent.
  • There are no third-party services, accounts, telemetry or analytics. Nothing leaves your machine unless you start or join a session.
  • The host window lists your computer's network interfaces (os.networkInterfaces()) only to show which addresses participants can use; they are not sent anywhere. Its “Copy” button writes the chosen address to the clipboard; the plugin never reads the clipboard.
  • Without a session password, traffic is not encrypted. Set a password when the network is shared with people you don't trust (for example, a public Hamachi network) — see below.

Installation

Everyone in a session needs the plugin, and the versions must match. The Excalidraw plugin must be enabled.

With BRAT (updates arrive automatically)

  1. Settings → Community plugins → Browse → install and enable BRAT.
  2. BRAT → Add Beta plugin → enter SHENID1/excalidraw-live-sync.
  3. Enable Excalidraw Live Sync in the list of community plugins.

Manually Download main.js, manifest.json and styles.css from the latest release into <vault>/.obsidian/plugins/excalidraw-live-sync/, then enable the plugin.

From source

npm install
npm run build
npm run install-plugin -- "C:/path/to/vault"

Usage

Host

  1. Open an Excalidraw drawing.
  2. Command palette → “Start live session (host)” (or the radio tower icon in the ribbon, or click Live: off in the status bar).
  3. A window lists your addresses — send participants the one on a network you share with them (for example, Radmin VPN).
  4. If Windows asks about the firewall, allow Obsidian on private networks.

Participant

  1. “Join live session”, enter IP or IP:port, your name and the password (if the host set one).
  2. Choose where to join:
    • New drawing — a file is created in the Excalidraw Live folder (configurable);
    • Current drawing (replace its contents) — the open drawing is replaced with the host's;
    • Current drawing (merge with the host's) — your elements are added to the host's board.

Everyone works on their own copy of the file in their own vault; Excalidraw autosaves the changes. The session ends when you close the drawing tab or open another file in it. After disconnecting, each participant keeps their copy as a regular local file.

The interface follows Obsidian's language: Russian when Obsidian is set to Russian, English otherwise.

Settings

Cursor name and color, port (default 47321), session password, folder for new drawings. A fresh install starts with a random name like “Guest 4821” — change it in the settings or in the join dialog.

Password and encryption

When the host sets a password:

  • the settings store a key derived from it (scrypt with a random salt), not the password itself;
  • the password never goes over the network: the host sends the salt and a one-time nonce, the participant answers with an HMAC of it, and the host proves the password back the same way; a captured answer is useless for the next connection;
  • after that, all traffic (drawing, images, cursors) is encrypted with AES-256-GCM using fresh keys per connection;
  • participants remember the key for the host's address, so the password is typed once;
  • if a participant entered a password but the host doesn't ask for one, the connection is refused rather than silently falling back to plaintext.

Without a password anyone on the network can join, and traffic is not encrypted.

How it works

  • src/net.ts — TCP server and client: a JSON-lines handshake, then length-prefixed frames (encrypted when a password is set) with keepalive. The host relays clients' messages to everyone else.
  • src/crypto.ts — the password key, password proofs and frame encryption.
  • src/session.ts — binds to the open ExcalidrawView: wraps its onChange / onPointerUpdate, sends changed elements and merges incoming ones by Excalidraw's own rule (higher version wins, ties go to the lower versionNonce), so all scenes converge. Remote changes don't enter the undo history.
  • Images (files) are sent whole; cursors are shown through Excalidraw's collaborators.

Releasing

Bump version in manifest.json and package.json, commit, and push a tag with the same number:

git tag 0.3.2
git push origin 0.3.2

A GitHub Action builds the plugin, attests the build provenance and publishes a release with main.js, manifest.json and styles.css.

Limitations

  • Without a password, traffic is not encrypted.
  • Plugin versions 0.1 and 0.2+ can't connect to each other — update everyone.
  • If the host disconnects, the session ends for everyone; reconnecting is manual.
  • Embedded links to vault files ([[...]], embeddables) open for other participants only if they have those files too.

License

MIT

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.