Doubles docs.
Everything you need to pair with Doubles: starting calls, the keyboard shortcuts, joining from a browser, and running your own server.
Getting started
- Install. Download Doubles for macOS 14 or later, on Apple silicon or Intel. Open the disk image and drag the app into Applications.
- Open it. A short welcome shows where the Doubles icon is in the menu bar and the permissions a call needs. From then on Doubles opens when you log in, so teammates can call you after a restart; the welcome lets you turn that off.
- Allow what a call needs. Screen & System Audio Recording, to share your screen and to record other people's voices. Accessibility, to let others control your Mac and to send system shortcuts to a Mac you control. Microphone. macOS asks for the camera, and on macOS 14 and 15 for speech recognition, the first time they're needed.
- Start a call. Click the menu bar icon, then Start a call. Doubles copies an invite link: send it to whoever you're pairing with. People who open it knock, and you let them in from the card under the call panel, or from the menu bar.
- Make a team. Invite to team… in the menu bar makes your team and copies its invite link. Teammates show up in the menu bar with whether they're around; click Call by one to call them, and their Mac rings.
In a call
The floating call panel has your microphone, camera, screen sharing and Leave. Its ⋯ menu has your microphone, speaker and camera, drawing, reactions, recording, transcription, who may control your screen, clipboard sharing, adding teammates, removing people and the coding agent.
Doubles asks you before anyone controls your Mac; Settings changes that. To drive someone else's Mac once they allow you, click in their shared screen: until you click, you only point. When someone drives your Mac, moving your mouse pauses them for a moment, and Control-Option-Command-period⌃⌥⌘. takes back control until you allow them again.
Transcripts and notes
Choose Transcribe Call from the call panel's ⋯ menu to transcribe your own speech, on your Mac. Each person who turns it on has their own speech transcribed on their Mac, and everyone on a Mac gets their lines, so ask the others to turn it on too. Doubles writes the transcript as Markdown. After the call, Apple Intelligence writes notes beside it, with a title, a summary, decisions and to-dos; a notice says when they're ready. Notes need macOS 26 with Apple Intelligence turned on. Open Transcripts Folder, under ⋯ in the menu bar, shows them.
Several Macs
To use your account on another Mac, choose Link Another Mac… under your name in the menu bar on a Mac you already use, enter the code it shows on the new Mac, and allow the new Mac there.
The command line
Settings › Advanced › Install Command Line Tool installs the doubles command. It talks to the app over a socket only you can open. Doubles was called Braces, so braces works too, for scripts written then.
$ doubles status # what Doubles is doing
$ doubles call ada # call a teammate
$ doubles join K7QF-M2XP # or paste an invite link
$ doubles mute | share | draw | react 🎉
$ doubles leave
Any program running as you could use that socket, so starting and joining calls, answering, letting people in, unmuting, turning the camera on, sharing your screen, control, recording, transcribing, joining teams and invite links work from it only after you turn on Settings › Advanced › Let the command line and scripts join calls, let people in and share my screen. Only Doubles can turn that on, in its own Settings: if another program changes the setting, Doubles ignores it and tells you. Muting, turning the camera off, stopping a share and leaving always work.
Triggers run your own scripts when calls start, connect and end, when people join and leave, and when screen sharing starts and stops, with the details in DOUBLES_* variables. Open Triggers Folder, under ⋯ in the menu bar or in Settings › Advanced, shows where they go, with a README.
Keyboard shortcuts
During a call these work from any app, with whichever keys type M, D and the period on your keyboard layout. Between calls, other apps keep them.
- Control-Command-M⌃⌘M
- Mute or unmute your microphone
- Control-Command-D⌃⌘D
- Draw on the screen you're watching or sharing, or stop drawing
- Control-Option-Command-period⌃⌥⌘.
- Take back control of your Mac from everyone
Watching or controlling a shared screen
- Control-Command-F⌃⌘F
- Take the shared screen's window out of full screen, even while you control that Mac
- Command-Tab⌘TabCommand-Space⌘Space
- These and other system shortcuts go to the Mac you control instead of yours. This needs Accessibility access on your Mac; you can turn it off in Settings.
- Control-Command-Q⌃⌘QShift-Command-Q⇧⌘QOption-Command-Escape⌥⌘Esc
- Lock the screen, log out and Force Quit always stay on your own Mac
In the menu bar
- Command-N⌘N
- Start a call
- Command-J⌘J
- Join a call
- Command-comma⌘,
- Settings
In the browser
- DD
- Draw on the screen you're watching (when you aren't controlling it)
- EscapeEsc
- Stop drawing
Browser guests
Anyone can join a Doubles call from a browser on Windows, Linux, ChromeOS or a Mac, with nothing to install and no account.
- Open the invite link you were sent and choose Join in this browser, or open
/app/on the Doubles server and type the call code. - Enter your name, pick a colour and click Join call. Someone in the call lets you in.
- Your microphone starts off: turn it on when you want to talk. You can also turn on your camera, and share your screen for the others to watch.
Move over a shared screen and everyone sees your pointer, with your name. Press DD or click ✏️ to draw on it, and EscapeEsc to stop. 😀 opens the reactions.
When the person sharing lets you control their Mac, click in their screen and use your own mouse and keyboard. With Ctrl → ⌘ on (the default, except on a Mac), your Ctrl key works as their ⌘, so Ctrl+C copies. In Chrome or Edge, click ⛶ for full screen, so that Ctrl+W, Ctrl+T and Alt+Tab go to their Mac too.
A browser can't be controlled, and only the Mac app transcribes and records. If the server's address starts with http:// rather than https://, your browser keeps the microphone, camera and screen sharing off; you can still watch, point, draw and control. If you can't hear anything, click anywhere on the page: browsers hold back a page's sound until you do.
Self-hosting
The Doubles server is a small Node.js program. It keeps accounts and teams, rings teammates, introduces the people in each call, serves the browser client and this website, and offers the Mac app for download. It never receives anyone's screen, voice or input.
On your network
From a copy of the Doubles repository, with Node 20 or later:
$ cd server && npm install && npm start
# ws://0.0.0.0:8787, with the browser client at /app/
On the internet
People on other networks need HTTPS and a TURN relay, for networks where a direct connection is impossible. scripts/deploy.sh sets up both on a fresh Ubuntu 22.04 or 24.04 machine you can reach over SSH as root: Node 22, Caddy with a certificate from Let's Encrypt, and coturn, with the server running as a systemd service.
$ scripts/deploy.sh root@203.0.113.7 pair.example.com you@example.com
# or with no domain, as 203-0-113-7.sslip.io:
$ scripts/deploy.sh root@203.0.113.7
Point pair.example.com at the machine first. When turn.pair.example.com points there too, the relay also works over TLS on port 443, for networks that allow nothing but web traffic. On Cloudflare, make these records DNS only, not proxied. Open TCP 22, 80, 443 and 3478, and UDP 3478 and 49152–65535. Run the script again to deploy a new version: calls in progress carry on. Run it with another name to move the server there: apps built for the old name keep using it while it points at the machine, and its pages redirect to the new one.
Your own Mac app
Package the app for your server and publish it there. Copies installed from it update themselves from your server.
$ SERVER_URL=wss://pair.example.com scripts/package.sh
$ scripts/deploy.sh --downloads root@pair.example.com
Back up the update key that package.sh creates in ~/.braces/release/update-key (installed copies accept only updates signed with it) and the server's state.json, which holds accounts and teams (with email sign-in and billing, also emails, signed-in browsers, and each team's Stripe customers and plan).
Settings
The server reads its settings from its environment: among them PUBLIC_HOST, the names people use for it, starting with the one links use; TURN_URLS and TURN_SECRET for a relay; TRUST_PROXY=1, together with PUBLIC_HOST, behind a proxy you run; and MAX_PARTICIPANTS, 6 people per call by default. deploy.sh writes them to /etc/braces/env each time it runs, keeping from before only the TURN secret, the names in PUBLIC_HOST that still point at the machine, and the settings for email sign-in and billing, so any other setting you add to that file lasts only until the next deploy.
Email sign-in, for an account page on this website and linking Macs by email, needs MAIL_PROVIDER (postmark or resend), MAIL_API_KEY, MAIL_FROM and PUBLIC_BASE_URL, the site's https address, which deploy.sh sets, and moves along when the server moves to a new name, unless you set it to another. Paid team plans then need STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET and STRIPE_PRICE_MONTHLY or STRIPE_PRICE_ANNUAL; without them, everything is free. The README has the steps.
The website's price line, footer links and sign-in link come from server/site/config.json, or from the JSON file that SITE_CONFIG names; anything left out isn't shown. deploy.sh copies server/, that file included, so fill it in before you deploy.
node scripts/check-server.mjs pair.example.com tries a server the way calls use it: HTTPS, the browser client, signaling, the published app and the relay. On a server with billing, only the Mac app starts calls, so it can't get to the relay, and says so.