Skip to content
karagöz docs

karagoz tap

Taps a point, or finds one node in the tree and taps its center.

  • Android emulator Done
  • Android device Done
  • iOS simulator Done
  • iOS device Done
~/app
karagoz tap <x> <y> [--duration <ms>] [--device <id>]
karagoz tap --text <label> [--timeout <ms>] [--duration <ms>] [--device <id>]
karagoz tap --id <resource-id> [--timeout <ms>] [--duration <ms>] [--device <id>]

Give exactly one of <x> <y>, --text or --id.

  • On Android: the screen on and unlocked. With the screen off, taps are dropped and the command still exits 0.
  • On Android, for --text and --id: no other UiAutomation client connected (Appium, Maestro, uiautomator events).
  • On an iOS simulator: Xcode 27 or newer, opened once.
  • On an iPhone: paired with the Mac, Developer Mode on, connected by USB cable, Settings > Developer > Enable UI Automation on, and Karagöz’s runner installed with install-runner.

Times on Android; the iOS sections below give theirs.

Point: <x> <y> Node: --text or --id
Speed About 0.2 s Adds one tree read, 2.5 to 3.3 s
Finds the target No: you give the pixels Yes, in the tree
Can wait for it No Yes, with --timeout
With another UiAutomation client Works Fails with AUTOMATION_BUSY
Option Default Meaning
<x> <y> A point in screen pixels. Non-negative, decimals allowed (12, 12.5).
--text <label> A node whose text or contentDesc equals the label: whole string, case-sensitive, no trimming. Invisible direction marks (U+200E and the like) are ignored on both sides.
--id <resource-id> A node whose resourceId equals the value, or ends with :id/<value>. --id save matches com.example:id/save.
--duration <ms> none Hold for this long (a long press). Whole milliseconds, 0 to 999999999.
--timeout <ms> 0 Keep reading the tree until a node matches or this much time has passed. Only with --text or --id.
--device <id> see Device selection
~/app
karagoz tap 540 1200
{"device":"emulator-5554","x":540,"y":1200}exit 0
~/app
karagoz tap --text Chrome
{"device":"emulator-5554","x":667.5,"y":2002.5,"element":{"class":"android.widget.TextView","text":"Chrome","contentDesc":"Chrome","clickable":true,"longClickable":true,"focusable":true,"bounds":[581,1905,754,2100]}}exit 0
~/app
karagoz tap 540 1200 --duration 10
{"device":"emulator-5554","x":540,"y":1200,"duration":10}exit 0
{
"device": "emulator-5554",
"x": 667.5,
"y": 2002.5,
"element": {
"class": "android.widget.TextView",
"text": "Chrome",
"contentDesc": "Chrome",
"clickable": true,
"longClickable": true,
"focusable": true,
"bounds": [581, 1905, 754, 2100]
}
}
device string
Serial, or the simulator's or iPhone's UDID.
x number
With <x> <y>: a point in screen pixels, non-negative, decimals allowed. With --text or --id: the center of element.
y number
With <x> <y>: a point in screen pixels, non-negative, decimals allowed. With --text or --id: the center of element.
element object
The matched node as ui-tree returns it, without children.
element.class string
Android class, e.g. android.widget.Button. Can be empty.
element.text string
Only when not empty. Jetpack Compose puts text in text, Flutter puts it in contentDesc.
element.contentDesc string
Only when not empty. Jetpack Compose puts text in text, Flutter puts it in contentDesc.
element.clickable boolean
Only when true.
element.longClickable boolean
Only when true.
element.focusable boolean
Only when true.
element.bounds array
[left, top, right, bottom] in screen pixels.
element.role string
On an iOS simulator, the accessibility subrole when there is one, else the role, without the AX prefix. On an iPhone, XCTest's element type.
element.label string
On iOS, only when not empty: what VoiceOver reads.
element.identifier string
On iOS, only when not empty: the app's accessibilityIdentifier.
duration number
Only with --duration, right after y: how long the tap was held, in whole milliseconds.
Read, tap, check
# 1. find the target
karagoz ui-tree
# 2. tap it
karagoz tap --text Chrome
# 3. read again: did the screen change?
karagoz ui-tree
  • The tap goes to the center of the node that matched, not to a clickable parent.
  • Nodes with zero-size bounds never match.
  • A parent and a child that both match are two matches: ELEMENT_AMBIGUOUS.
  • If the keyboard is visible and the node’s center is inside it, the tap is refused with ELEMENT_COVERED. Only the keyboard is checked; bubbles and picture-in-picture windows are not.
  • Only “no match” triggers another read, and it starts right away. The last read can end up to one read (about 3 s) past the timeout. The tap itself is never repeated.
  • The screen can change between the read and the tap; the tap then lands on the old point.
CodeWhen
INVALID_ARGSNo target or more than one ('tap' takes <x> <y>, --text or --id), a single coordinate ('tap' needs <x> <y>), --timeout with a point, or a malformed number.
ELEMENT_NOT_FOUNDno node with text or contentDesc 'Save' in com.example (1 read in 2.6 s).
ELEMENT_AMBIGUOUSThe message lists up to five matches with class and bounds. Pick one and tap its coordinates.
ELEMENT_COVEREDThe node is under the keyboard. Close the keyboard with karagoz key BACK.

Node taps also get every ui-tree error. Every tap can also get INPUT_BLOCKED, the device selection errors and the adb errors.

  • A long press with --duration: View and Compose use the device’s long-press setting (settings get secure long_press_timeout; 400 ms on stock Android, Samsung offers 300 to 1500 ms), Flutter 500 ms.
  • Points are not checked against the screen size.

Same arguments and output. The point goes to the simulator’s own input service as a real touch, and --duration holds it there.

{
"device": "27024DC1-EDB0-4BF2-8010-08FE3936BAB6",
"x": 603,
"y": 1015,
"element": {
"role": "Button",
"label": "Tap me 0",
"identifier": "tap-button",
"bounds": [48, 937, 1158, 1093]
}
}
  • --text matches a node’s label or value, --id its identifier; both whole and case-sensitive, direction marks ignored. There is no :id/ rule.
  • The node is tapped at its center like a finger, so what covers it gets the tap.
  • There is no keyboard check on a simulator.
  • The message for no match is no node with label or value 'Save' in the frontmost app (1 read in 0.3 s).
  • A tap takes about 0.6 s; a node tap adds one tree read, about 0.3 s.
  • The first of ui-tree, tap, swipe, text or key on a simulator compiles a small helper, which takes a few seconds.
  • Errors:

Same arguments and output. Karagöz’s runner plays the touch; it is started and stopped as for ui-tree, and installed with install-runner. The pixels are turned into the panel’s points for the interface orientation.

  • --text and --id match as on the simulator. Unlike there, a node whose center the on-screen keyboard covers is refused with ELEMENT_COVERED (a key of the keyboard itself can be tapped). Hide the keyboard first, for example with key ENTER in a single-line field.
  • --duration holds for that long. For a 0.5 s long press, 500 ms did not trigger it and 550 ms did.
  • A tap takes about 0.6 s; the first after the runner stopped about 3.3 s.
  • Errors: those of ui-tree on an iPhone, with HELPER_FAILED for a touch the runner could not play.
MCP equivalenttap {"text":"Chrome"}MCP tools

Arguments: x, y, text, id, duration, timeout, device. The names are the CLI's option and positional names.

karagoz ui-tree
Find a node's text, id and bounds before the tap, and read the screen again after it.
karagoz install-runner
Install the runner that plays the touch on an iPhone.