karagoz screenshot
Saves the screen as a PNG at full device resolution, never scaled, and prints where it went with the metadata needed to measure against it.
- Android emulator Done
- Android device Done
- iOS simulator Done
- iOS device Done
karagoz screenshot [--out <path>] [--device <id>]Before you start
Section titled “Before you start”- On an iOS simulator: Xcode, opened once, and a booted simulator (on Xcode 27,
xcrun simctl boot <name>; on older ones,open -a Simulator). - On an iPhone: paired with the Mac, Developer Mode on (Settings > Privacy & Security > Developer Mode), and Xcode 27 or newer, opened once: Xcode 26’s
devicectlhas nodevice capture screenshot.
Options
Section titled “Options”| Option | Default | Meaning |
|---|---|---|
--out <path> |
a new file under the temp directory | Where to write the PNG; must end in .png, in any letter case. |
--device <id> |
see Device selection | An adb serial, a simulator’s or iPhone’s UDID, or a name. |
Examples
Section titled “Examples”Save to a file
Section titled “Save to a file”karagoz screenshot --out home.png{"path":"/Users/me/home.png","device":"emulator-5554","pixels":{"width":1080,"height":2400},"logical":{"width":411.42857142857144,"height":914.2857142857143},"scale":2.625,"safeArea":{"top":63,"right":0,"bottom":63,"left":0},"rotation":0}exit 0Output
Section titled “Output”An iPhone 17 simulator (macOS, Xcode 27), without --out:
{ "path": "/var/folders/.../T/karagoz/27024DC1-EDB0-4BF2-8010-08FE3936BAB6-20261012T182033769Z.png", "device": "27024DC1-EDB0-4BF2-8010-08FE3936BAB6", "pixels": { "width": 1206, "height": 2622 }, "logical": { "width": 402, "height": 874 }, "scale": 3, "safeArea": null, "rotation": 0}pathstring- Absolute path of the PNG.
devicestring- The adb serial, or the simulator's or iPhone's UDID.
pixelsobject- Size of the PNG, read from the file itself.
pixels.widthnumber- Size of the PNG, read from the file itself.
pixels.heightnumber- Size of the PNG, read from the file itself.
logicalobjectpixels / scale, not rounded.logical.widthnumberpixels / scale, not rounded.logical.heightnumberpixels / scale, not rounded.scalenumber- Physical pixels per density-independent pixel on Android, per point on iOS (Coordinates). See below.
safeAreaobject or null- Pixels of this PNG covered by the status bar, navigation bar, caption bar or display cutout.
nullon iOS. See below. safeArea.topnumber- Pixels of this PNG covered by the status bar, navigation bar, caption bar or display cutout.
safeArea.rightnumber- Pixels of this PNG covered by the status bar, navigation bar, caption bar or display cutout.
safeArea.bottomnumber- Pixels of this PNG covered by the status bar, navigation bar, caption bar or display cutout.
safeArea.leftnumber- Pixels of this PNG covered by the status bar, navigation bar, caption bar or display cutout.
rotationnumber or null- Screen rotation in degrees:
0,90,180or270.nullon Xcode 26 and earlier, or whendevicectlfails. See below.
How scale is read:
- Android: density / 160, using the override density if one is set (
adb shell wm density). - Simulator: its
SIMULATOR_MAINSCREEN_SCALE. - iPhone: the
pointScalethatdevicectl device info displaysreports for the primary display. - On both iOS targets a 1080x2340 or 2340x1080 PNG (iPhone 12 mini, 13 mini) gets
2.88(1080 / 375): the simulator reports 3 there, but apps lay out 375 points wide.
In safeArea a hidden bar counts as 0, and the keyboard and gesture areas are not included. It is null on iOS: only the app itself can read its safe area, and neither the simulator nor devicectl exposes another source.
On iOS with Xcode 27, rotation is the interface orientation from devicectl, in Android’s meaning: turned counter-clockwise (landscape left) is 90.
On iOS the PNG is exactly what simctl or devicectl wrote; Karagöz does not rotate or re-encode it.
- On a simulator with Xcode 27, the PNG follows the interface orientation. With Xcode 26 it is the panel in portrait, and a landscape app’s UI is drawn sideways in it.
- A simulator’s PNG has square corners, not rounded ones, and the Dynamic Island area is black pixels.
- An iPhone’s PNG follows the interface orientation and has 16 bits per channel and a Display P3 color profile.
File location
Section titled “File location”- Without
--out:<temp dir>/karagoz/<device id>-<UTC timestamp>.png, for example/var/folders/.../T/karagoz/emulator-5554-20260926T101530123Z.png.- The device id is a UDID on iOS. Characters other than letters, digits,
.,_and-in it become_. - The temp directory follows
TMPDIR. - The
karagozdirectory is created private to your user (mode 0700) and must be a real directory you own. - The file is created with mode 0600 and never overwrites.
- The device id is a UDID on iOS. Characters other than letters, digits,
- With
--out: relative paths resolve against the current directory, missing parent directories are created, and an existing.pngis overwritten. - Karagöz never deletes screenshots. The size of one capture:
- about 1.4 MB at 1080x2400
- about 2.9 MB from a 1206x2622 simulator
- 1 to 5 MB from a 1290x2796 iPhone, depending on what is on screen
Errors
Section titled “Errors”| Code | When |
|---|---|
CAPTURE_FAILED | On Android: screencap returned something other than a whole PNG. Its message is included. |
CAPTURE_FAILED | On Android: the density, display size, rotation or insets could not be read (cannot read <value> from <command>). |
CAPTURE_FAILED | On Android: the screen rotated or resized during the capture (display is WxH but the screenshot is WxH). |
CAPTURE_FAILED | On Android with more than one display: screencap's warning comes back as this error. |
CAPTURE_FAILED | On a simulator: simctl printed something other than a whole PNG (its text, or simctl returned no image data). |
CAPTURE_FAILED | On a simulator: the scale could not be read (cannot read scale from 'simctl getenv' (got '<value>')). |
CAPTURE_FAILED | On an iPhone: devicectl returned no image data, or cannot read scale from 'devicectl device info displays'. |
CAPTURE_FAILED | On an iPhone: the screen rotated during the capture (rotation <r>, screenshot <w>x<h>) when the phone turned between the capture and the display read. |
SIMCTL_FAILED | On iOS the capture failed; the message is simctl's text. The first capture right after a boot can fail with Error creating the image. |
SIMCTL_TIMEOUT | After 30 s. |
SIMCTL_NOT_FOUND | Without Xcode. |
DEVICE_NOT_READY | On an iPhone that is unpaired or pairingInProgress, before any capture. |
DEVICE_NOT_READY | On an iPhone, from the capture: Developer Mode is off, the phone is no longer paired with this Mac, or it is locked since it restarted. In both cases the message says what to do on the phone. |
NOT_SUPPORTED | On an iPhone, when this Mac's devicectl predates Xcode 27. |
DEVICECTL_TIMEOUT | On an iPhone, after 30 s. |
DEVICECTL_FAILED | On an iPhone, with devicectl's text for any other failure. |
WRITE_FAILED | The file could not be written, or the default directory is not yours (pass --out). Two captures of one device in the same millisecond without --out: the second fails. |
INVALID_ARGS | '<absolute path>' is not a .png file for an --out that does not end in .png, before any device call. |
Plus the device selection errors, the other INVALID_ARGS cases and the adb errors.
- A capture takes about:
- 1 s on the emulator
- 0.5 s on a phone over USB
- 0.6 s on a simulator
- 0.9 s on an iPhone over USB. The first call after the iPhone was plugged in or sat idle takes a few seconds more while devicectl connects to it.
- A screen that is off, or an app that sets
FLAG_SECURE, gives a black PNG and exit0; so does a locked iPhone with its screen off. - Some Android 14 builds refuse the capture instead while a
FLAG_SECUREwindow or the lock screen’s PIN pad is showing:CAPTURE_FAILEDwithscreencap returned no data. - If the density changes during a capture,
scaleandsafeAreacan disagree for that one capture.
MCP equivalent
Section titled “MCP equivalent”Arguments: out, inline, device. The names are the CLI's option and positional names.