Start and stop Sidecar from the command line.
Sidecar turns an iPad into a second display for a Mac, and macOS only offers it through menus. sidecarctl lets a script or a keyboard shortcut do the connecting, and choose between the cable and Wi-Fi.
sidecarctl connectIt can also route the session through a virtual display. In my own use, on an iPad Pro 13-inch (M4), that made Sidecar noticeably more responsive than it is out of the box. Whether it does the same for you depends on your iPad and your Mac, and it may change nothing. See Boost before expecting anything from it.
- Connects and disconnects Sidecar without touching a menu.
- Chooses the connection: cable only, Wi-Fi only, or cable when there is one.
- Optionally routes the session through a virtual display, which may make the iPad more responsive.
- Reports what is running, as text or JSON, with exit codes a script can rely on.
- A Mac with Apple silicon. Intel Macs are not supported.
- macOS 27. Other versions are untested.
- An iPad that already works with Sidecar on this Mac. If Sidecar does not connect from Control Center, it will not connect from here either.
sidecarctl uses two parts of macOS that Apple does not document: the
SidecarCore framework, following the approach of
SidecarLauncher, and
CoreGraphics' virtual display classes. A macOS update can break either one. If
the tool stops working after an update, check for a newer release, and open an
issue with the output of sw_vers if there is none.
Tested with an iPad Pro 13-inch (M4). Other iPads are untested.
With Homebrew:
brew install tsilenzio/tap/sidecarctlOr download the tarball from the
releases page, unpack it, and
move sidecarctl somewhere on your PATH. The binary is signed and notarized.
To build it yourself, see Building.
See which iPads the Mac can reach:
$ sidecarctl devices
11111111-1111-1111-1111-111111111111 Test iPad
Connect. With one iPad reachable there is no need to name it:
sidecarctl connectDisconnect:
sidecarctl disconnectConnect through a virtual display, which may make the iPad more responsive.
The command keeps running for as long as the session lasts. Press Ctrl-C, or run
sidecarctl boost --stop from elsewhere, and the session ends with it.
sidecarctl connect --boostUse the cable or nothing. Exits 8 if no iPad is plugged in.
sidecarctl connect --connection wiredUse Wi-Fi even when the cable is in.
sidecarctl connect --connection wirelessPick one iPad out of several, by name or by the UUID from devices. A UUID
stays usable in a script without the iPad's name appearing in it.
sidecarctl connect "Test iPad"
sidecarctl connect 11111111-1111-1111-1111-111111111111Sharper text with a boost. --retina doubles the pixels each way, which is
four times the pixels for the Mac to draw and send.
sidecarctl connect --boost --retinaGive a sleeping iPad time to wake. Checks again every 3 seconds, up to 10 more times.
sidecarctl connect --retries 10See what is running.
$ sidecarctl status
connected to Test iPad, wired, 60 fps
boost running
Boost a session that is already running, such as one started from Control Center. Here stopping the boost leaves the session up.
sidecarctl boostsidecarctl help prints the list below. sidecarctl help <command>, or --help
on any command, prints that command's usage and options. Run with no arguments,
sidecarctl prints the same overview.
devices list the iPads this Mac can reach
connect start a Sidecar session, through a virtual display with --boost
disconnect end a Sidecar session
status show the live session and whether a boost is running
boost route a session that is already up through a virtual display
help show the overview, or `help <command>` for one command
--version print sidecarctl's own version
A mistake in the arguments is named, followed by the help for the command it was made in:
$ sidecarctl connect --connection either
sidecarctl: `--connection` does not take `either`. It wants one of prefer-wired, wired, wireless, system.
sidecarctl devices [--verbose | --json]
Prints each reachable iPad on its own line as its UUID, a tab, and its name.
| Option | Effect |
|---|---|
--verbose |
Adds a tab and the status value Sidecar reports for the iPad |
--json |
Prints one line of JSON |
connect and disconnect take a device as either its name or its UUID, without
regard to case. With one iPad reachable the device can be left out.
sidecarctl connect [<device>] [--connection <how>] [--boost [--hz <rate>] [--retina]]
[--retries <count>] [--framerate <fps>] [--low-latency]
[--ignore-not-ready]
Starts a Sidecar session. A session that already matches what was asked for is
kept, and connect exits 0. A session over a different connection or at a
different framerate is ended and replaced.
--connection selects how the session is carried:
| Value | Behavior |
|---|---|
prefer-wired |
The default. Over the cable when an iPad is attached by USB. Over Wi-Fi when none is attached or when the cable does not connect in two tries. |
wired |
Over the cable. Exits 8 when no iPad is attached by USB. |
wireless |
Over Wi-Fi. |
system |
Whichever Sidecar picks. |
| Option | Effect |
|---|---|
--boost |
Once connected, routes the session through a virtual display. See boost. |
--hz <rate> |
With --boost, the rate the virtual display is set to, 120 unless given |
--retina |
With --boost, twice the pixels each way |
--retries <count> |
That many further tries, 3 seconds apart. 0 unless given. See Troubleshooting for why. |
--ignore-not-ready |
Tries even when the iPad reports it is not ready |
--framerate <fps> |
The rate Sidecar streams at, 60 unless given. Sidecar's own setting, separate from --boost. |
--low-latency |
Turns on Sidecar's low latency mode |
sidecarctl disconnect [<device>]
Ends the session to an iPad. Exits 0 when there is no session to end. A boost running on the session stops with it.
sidecarctl status [--json]
Prints each live session with its iPad, whether it is wired or wireless, and its framerate, then whether a boost is running. It answers with or without a reachable iPad.
sidecarctl boost [--hz <rate>] [--retina]
sidecarctl boost --stop
boost creates a virtual display and has Sidecar's display mirror it. The
virtual display is set to a higher refresh rate than Sidecar's own, so the Mac
draws at that rate and Sidecar streams what it drew. --retina also moves the
display to its Retina mode at the same size.
On my iPad Pro 13-inch (M4) this made Sidecar noticeably more responsive. It is not a promise of any particular refresh rate on the iPad. What reaches the screen depends on the iPad, the Mac, the connection, and the macOS version, none of which sidecarctl can measure, and the result may be no different from plain Sidecar. Try it, and stop using it if it does not help.
boost needs a Sidecar session to be running. It keeps running until the
session ends or sidecarctl boost --stop is run, and the mirroring ends with it.
connect --boost does both in one command: it starts the session, or keeps one
that already matches, then runs the boost on it, taking --hz and --retina. The
command keeps running for the life of the session. The two end together: when the
session ends the boost stops, and when the boost is stopped, with
sidecarctl boost --stop or by interrupting the command, the session is ended
too. If the boost cannot be set up the command exits with the boost's error and
the session is left running as plain Sidecar.
--hz sets the rate the virtual display is created at, 120 unless given. That
is the rate the Mac draws at. Nothing on the Mac reports what the iPad itself
can show, so the rate is not checked against it, and what the iPad shows may be
lower.
While a boost runs, macOS lists one more display, named after the iPad. It can be arranged in System Settings like any other, and macOS remembers where it was put.
devices --json and status --json print one line of JSON, so a caller reads
fields and does not parse messages:
$ sidecarctl devices --json
[{"connected":true,"id":"11111111-1111-1111-1111-111111111111","name":"Test iPad","notReady":false,"status":"0x1880306"}]
$ sidecarctl status --json
{"boost":4242,"sessions":[{"connection":"wired","displayID":34,"framerate":60,"id":"11111111-1111-1111-1111-111111111111","lowLatency":false,"name":"Test iPad"}]}
boost is the process ID of the running boost. connection is wired or
wireless. A field with no value is left out, so boost is absent when none is
running. A field keeps its name and meaning from one release to the next, and new
fields may be added.
An option the tool does not know is an error, exit 1, and is never read as a device's name.
A code keeps its meaning from one release to the next.
| Code | Meaning |
|---|---|
| 0 | Done |
| 1 | Bad arguments |
| 2 | No reachable devices, or no Sidecar display for boost |
| 3 | No device with that name or UUID |
| 4 | SidecarCore or CoreGraphics reported an error |
| 5 | SidecarCore could not be loaded |
| 6 | No device given and more than one reachable |
| 7 | A boost is already running |
| 8 | The connection asked for is unavailable |
| 9 | The device reports it is not ready |
Those dialogs come from macOS, one for each connection attempt Sidecar refuses, and sidecarctl cannot turn them off. It tries to avoid causing them:
- Retries are off unless
--retriesis given, since each failed try is another dialog. - Before connecting,
connectreads the status value Sidecar reports for the iPad. When it is one recorded as not ready,connectexits 9 without asking Sidecar, so no dialog appears.
The iPad is listed but would refuse the connection, as one that has sat unused
for a while may. Wake and unlock it and run connect again, or use
--retries 10 to keep checking for about half a minute. A check costs no dialog.
--ignore-not-ready attempts the connection anyway.
The not-ready check does not catch every refusal. What puts an iPad into the recorded state is not known, and a connection can still fail, with its dialog, from a state that reports as ready. Only status values seen on a real device are recorded, and any other value is attempted as usual, so an iPad that reports differently is never refused. The recorded values so far come from one iPad model.
If this happens on your iPad, the output of sidecarctl devices --verbose at
that moment is worth reporting in an issue.
No iPad is attached by USB as far as the Mac can tell. Check the cable.
Needs Apple's command line tools (xcode-select --install).
xcrun swift build -c releaseThe binary is .build/release/sidecarctl.
The unit tests cover argument parsing, the help and the messages for mistaken
arguments, device matching, the JSON output, and which connections are tried in
what order. With Xcode selected (xcode-select -p
names Xcode.app):
xcrun swift testWith only the command line tools, the test macros' plugin has to be pointed at:
xcrun swift test -Xswiftc -plugin-path \
-Xswiftc /Library/Developer/CommandLineTools/usr/lib/swift/host/plugins/testingscripts/device-test.sh runs the built binary against a real iPad. It needs one
reachable iPad, unlocked and awake, and it starts and ends Sidecar sessions.
scripts/release.sh builds, signs, and notarizes the tagged commit, and leaves a
tarball and its checksum in dist/. It needs a Developer ID Application
certificate and stored notarization credentials, and its header says how to
supply both.
MIT. See LICENSE.