Skip to content
karagöz docs

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
~/app
karagoz screenshot [--out <path>] [--device <id>]
  • 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 devicectl has no device capture screenshot.
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.
~/app
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 0

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
}
path string
Absolute path of the PNG.
device string
The adb serial, or the simulator's or iPhone's UDID.
pixels object
Size of the PNG, read from the file itself.
pixels.width number
Size of the PNG, read from the file itself.
pixels.height number
Size of the PNG, read from the file itself.
logical object
pixels / scale, not rounded.
logical.width number
pixels / scale, not rounded.
logical.height number
pixels / scale, not rounded.
scale number
Physical pixels per density-independent pixel on Android, per point on iOS (Coordinates). See below.
safeArea object or null
Pixels of this PNG covered by the status bar, navigation bar, caption bar or display cutout. null on iOS. See below.
safeArea.top number
Pixels of this PNG covered by the status bar, navigation bar, caption bar or display cutout.
safeArea.right number
Pixels of this PNG covered by the status bar, navigation bar, caption bar or display cutout.
safeArea.bottom number
Pixels of this PNG covered by the status bar, navigation bar, caption bar or display cutout.
safeArea.left number
Pixels of this PNG covered by the status bar, navigation bar, caption bar or display cutout.
rotation number or null
Screen rotation in degrees: 0, 90, 180 or 270. null on Xcode 26 and earlier, or when devicectl fails. 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 pointScale that devicectl device info displays reports 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.
  • 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 karagoz directory 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.
  • With --out: relative paths resolve against the current directory, missing parent directories are created, and an existing .png is 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
CodeWhen
CAPTURE_FAILEDOn Android: screencap returned something other than a whole PNG. Its message is included.
CAPTURE_FAILEDOn Android: the density, display size, rotation or insets could not be read (cannot read <value> from <command>).
CAPTURE_FAILEDOn Android: the screen rotated or resized during the capture (display is WxH but the screenshot is WxH).
CAPTURE_FAILEDOn Android with more than one display: screencap's warning comes back as this error.
CAPTURE_FAILEDOn a simulator: simctl printed something other than a whole PNG (its text, or simctl returned no image data).
CAPTURE_FAILEDOn a simulator: the scale could not be read (cannot read scale from 'simctl getenv' (got '<value>')).
CAPTURE_FAILEDOn an iPhone: devicectl returned no image data, or cannot read scale from 'devicectl device info displays'.
CAPTURE_FAILEDOn 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_FAILEDOn 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_TIMEOUTAfter 30 s.
SIMCTL_NOT_FOUNDWithout Xcode.
DEVICE_NOT_READYOn an iPhone that is unpaired or pairingInProgress, before any capture.
DEVICE_NOT_READYOn 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_SUPPORTEDOn an iPhone, when this Mac's devicectl predates Xcode 27.
DEVICECTL_TIMEOUTOn an iPhone, after 30 s.
DEVICECTL_FAILEDOn an iPhone, with devicectl's text for any other failure.
WRITE_FAILEDThe 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 exit 0; so does a locked iPhone with its screen off.
  • Some Android 14 builds refuse the capture instead while a FLAG_SECURE window or the lock screen’s PIN pad is showing: CAPTURE_FAILED with screencap returned no data.
  • If the density changes during a capture, scale and safeArea can disagree for that one capture.
MCP equivalentscreenshot {"out":"home.png"}MCP tools

Arguments: out, inline, device. The names are the CLI's option and positional names.