patchright-cli 0.9.1__py3-none-any.whl → 0.11.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
1
  """patchright-cli — Undetected browser automation CLI using Patchright."""
2
2
 
3
- __version__ = "0.9.1"
3
+ __version__ = "0.11.0"
@@ -1,6 +1,6 @@
1
1
  """Allow running as `python -m patchright_cli`."""
2
2
 
3
- from patchright_cli.cli import main
3
+ from patchright_cli._entry import main
4
4
 
5
5
  if __name__ == "__main__":
6
6
  main()
@@ -0,0 +1,26 @@
1
+ """Console-script entry point with a `--version` fast path.
2
+
3
+ Agents probe `--version` constantly, so a bare version flag is answered here
4
+ from the leaf `patchright_cli/__init__.py`, before cli.py pulls in click and
5
+ the daemon (and with it Patchright). Everything else goes to cli.main().
6
+ """
7
+
8
+ import sys
9
+
10
+ _VERSION_FLAGS = ("-v", "-V", "--version")
11
+
12
+
13
+ def main() -> None:
14
+ if len(sys.argv) == 2 and sys.argv[1] in _VERSION_FLAGS:
15
+ from patchright_cli import __version__
16
+
17
+ sys.stdout.write(__version__ + "\n")
18
+ return
19
+
20
+ from patchright_cli.cli import main as cli_main
21
+
22
+ cli_main()
23
+
24
+
25
+ if __name__ == "__main__":
26
+ main()
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: patchright-cli
3
- description: Anti-detect browser automation using Patchright (undetected Playwright fork). Use when you need to interact with websites that block regular Playwright/Chrome DevTools, such as Akamai/Cloudflare-protected sites. Provides the same command interface as playwright-cli but bypasses bot detection. Use this skill whenever the user asks to automate a browser, scrape a website, fill forms, log into sites, take screenshots, or do anything involving Chrome automation — especially if the target site has bot protection like Cloudflare or Akamai.
3
+ description: Anti-detect browser automation using Patchright (undetected Playwright fork). Use when you need to interact with websites that block regular Playwright/Chrome DevTools, such as Akamai/Cloudflare-protected sites. Uses playwright-cli style commands (not a drop-in replacement) but bypasses bot detection. Use this skill whenever the user asks to automate a browser, scrape a website, fill forms, log into sites, take screenshots, or do anything involving Chrome automation — especially if the target site has bot protection like Cloudflare or Akamai.
4
4
  ---
5
5
 
6
6
  # Anti-Detect Browser Automation with patchright-cli
@@ -28,7 +28,7 @@ patchright-cli screenshot # capture the page
28
28
  patchright-cli close # done
29
29
  ```
30
30
 
31
- Every interaction follows: **open -> snapshot -> read refs -> interact -> snapshot again -> repeat**. Refs are ephemeral -- they change on every page update. If a ref fails, re-snapshot.
31
+ Every interaction follows: **open -> snapshot -> read refs -> interact -> snapshot again -> repeat**. A ref (`e5`, or `f3e5` inside an iframe and after a navigation) names one element until it leaves the page; a ref whose element is gone fails fast with `no longer matches an element` -- re-snapshot then. Refs are per tab: after `tab-select`, use the snapshot it prints. A click that opens a popup makes the popup current, and the popup's first-document refs (`e1`, `e2`, ...) can reuse numbers from the opener, so use the snapshot printed after the click.
32
32
 
33
33
  ## Command chaining
34
34
 
@@ -101,6 +101,8 @@ These go before the command:
101
101
  --show-port=9322 # Dashboard port (default: 9322)
102
102
  --raw # Strip page/snapshot decorations from output
103
103
  --json # Wrap full response as JSON ({success, output, ...})
104
+ --toon # TOON for results with structured data (list, tab-list, cookie-list,
105
+ # find, console, network, url, title, ...); others print as usual
104
106
  ```
105
107
 
106
108
  These go *after* the command instead:
@@ -147,9 +149,9 @@ snapshot <ref> # Subtree of a specific element
147
149
  snapshot --selector="#main" # Subtree of a CSS selector -- must match exactly
148
150
  # one element. No ref needed, so
149
151
  # this works before the first snapshot
150
- snapshot --depth=N # Limit depth
151
- snapshot -i # Interactive elements only
152
- snapshot --boxes # Append [box=x,y,w,h] to each [ref=eN] line
152
+ snapshot --depth=N # Levels 0..N; a cut node ends in `# +N refs`
153
+ snapshot -i # Interactive elements (and named landmarks around them)
154
+ snapshot --boxes # Append [box=x,y,w,h] (page coordinates, iframes too)
153
155
  ```
154
156
 
155
157
  ### Searching instead of snapshotting
@@ -163,8 +165,14 @@ patchright-cli find --regex "sign (in|up)" # regex, case-insensitive
163
165
  patchright-cli find --regex "/Sign In/" # slash form carries flags (i, m, s)
164
166
  patchright-cli find "price" --all # include text/paragraph nodes
165
167
  patchright-cli find "hide" --limit=50 # default limit is 20
168
+ patchright-cli find --role=button --description="Deletes" # role + accessible description
166
169
  ```
167
170
 
171
+ The snapshot never shows accessible descriptions (`aria-describedby`,
172
+ `aria-description`, a `title` that is not the name). To target an element by
173
+ one, use `find --role=<role>` with `--name` and/or `--description`: substring
174
+ and case-insensitive, `/regex/i`, or whole with `--exact`. It returns refs.
175
+
168
176
  `find` searches links, buttons, inputs and headings by default — the things
169
177
  you can act on. Use `--all` when you are looking for page *content* rather
170
178
  than a control.
@@ -174,13 +182,13 @@ controls stay distinguishable:
174
182
 
175
183
  ```
176
184
  # table > rowgroup > cell "407 points by pluc 4 hours ago | hide | 321 ..."
177
- - link "hide": [ref=e49]
185
+ - link "hide" [ref=e49]:
178
186
  - /url: hide?id=49489982
179
187
  ```
180
188
 
181
- Refs from `find` are numbered across the whole page and are immediately
182
- usable with `click`, `fill`, and the rest. They stay valid until the next
183
- `snapshot` or `find`.
189
+ Refs from `find` are the same refs `snapshot` prints and are immediately
190
+ usable with `click`, `fill`, and the rest. A hit with no ref of its own (a
191
+ `text:` line or an `option`) names the element to act on as `[in=e12]`.
184
192
 
185
193
  When output says `Found 20 of 340 matches`, narrow the query rather than
186
194
  raising `--limit`.
@@ -198,6 +206,8 @@ drop <ref> --path=./file.png # Drop file onto element (HTML5 drop from outside)
198
206
  drop <ref> --data="text/plain=hello" # Drop arbitrary MIME data
199
207
  ```
200
208
 
209
+ `drop` fails (exit 1) when the target does not accept drops, meaning its `dragover` handler does not call `preventDefault()`. Before, it reported success without anything being dropped. Drop onto the element that handles the drop, not onto a wrapper around it.
210
+
201
211
  ### Form input
202
212
 
203
213
  ```bash
@@ -235,14 +245,6 @@ press <key> # Keypress (Enter, ArrowDown, etc.)
235
245
  keydown <key> / keyup <key> # Hold/release key
236
246
  ```
237
247
 
238
- ### Mouse
239
-
240
- ```bash
241
- mousemove <x> <y> # Move to coordinates
242
- mousedown / mouseup # Button down/up
243
- mousewheel <dx> <dy> # Scroll wheel
244
- ```
245
-
246
248
  ### Tabs
247
249
 
248
250
  ```bash
@@ -306,7 +308,7 @@ dialog-dismiss # Dismiss next dialog
306
308
  ### DevTools
307
309
 
308
310
  ```bash
309
- console # Show console messages
311
+ console # Start capture / show captured console messages
310
312
  console warning # Filter by level
311
313
  network # Show network requests (each line is `#<id> METHOD STATUS URL`)
312
314
  requests # Alias for `network`
@@ -318,6 +320,38 @@ highlight <ref> # Persistent overlay on element [--style=CSS]
318
320
  highlight <ref> --hide # Remove overlay; `highlight --hide` clears all
319
321
  ```
320
322
 
323
+ The first `console` call starts CDP Runtime capture across this session's existing
324
+ and future pages, including popups. Earlier messages are unavailable: call it
325
+ before reproducing an issue, then again to read messages. Capture makes CDP
326
+ detectable until the session closes; `console --clear` only clears the buffer.
327
+
328
+ A highlight is page-visible while shown (an `<x-pw-glass>` element under `<html>`);
329
+ `--hide` removes the element once no highlight is left. `pick-locator` refuses to
330
+ run without `--detectable`: Playwright's recorder then stays in every page of the
331
+ session (`window.playwright`, `__pw_*` globals, an `<x-pw-glass>` element it
332
+ re-adds) until the session closes, so use a throwaway session for it.
333
+
334
+ ### Debugger (step through a command's browser calls)
335
+
336
+ ```bash
337
+ debugger-pause # Arm: the next page action, navigation or eval pauses
338
+ click e3 # Replies at once: "Paused before: Evaluate (held: `click e3`)"
339
+ snapshot # Other commands still run while paused, actions included
340
+ debugger-step # Run that call, pause before the next ("Click ...")
341
+ debugger-resume # Let the held command finish, turn the debugger off
342
+ debugger-status # off | armed | paused + call title and held command
343
+ ```
344
+
345
+ This is Playwright's action debugger, not a JavaScript debugger: it holds
346
+ patchright-cli's own calls in the driver, sends nothing to Chrome, and page
347
+ scripts keep running, so pages cannot detect it. Only page actions, navigation,
348
+ `eval` and element getters pause; `snapshot`, `title`, cookies, `state-save`,
349
+ `tab-new` and `highlight` run straight through (the reply says so) and leave it
350
+ armed. While one call is held, other commands, actions included, run at once,
351
+ so their side effects can land before the held one's. After `debugger-step` the
352
+ debugger stays armed until `debugger-resume`, which also cancels an armed pause
353
+ nothing has hit. `close` while paused resumes and closes.
354
+
321
355
  ### Recording and capture
322
356
 
323
357
  ```bash
@@ -352,36 +386,201 @@ set-media print # screen | print
352
386
  clear-media
353
387
  ```
354
388
 
355
- ### Storage
356
-
357
- ```bash
358
- cookie-list / cookie-get / cookie-set / cookie-delete / cookie-clear
359
- cookie-export / cookie-import
360
- localstorage-list / localstorage-get / localstorage-set / localstorage-delete / localstorage-clear
361
- sessionstorage-list / sessionstorage-get / sessionstorage-set / sessionstorage-delete / sessionstorage-clear
362
- state-save <file> / state-load <file>
363
- ```
364
-
365
- ### Network
366
-
367
- ```bash
368
- route "<pattern>" [options] # Mock requests (--status, --body, --content-type, --header)
369
- route-list / unroute # Manage routes
370
- network-state-set offline # Simulate offline
371
- network-state-set online # Restore connectivity
372
- ```
373
-
374
- ### Sessions
375
-
376
- ```bash
377
- list # List active sessions
378
- close-all # Close all sessions
379
- kill-all # Force-kill all + stop daemon
380
- delete-data # Delete session profile data
381
- profile-list # List profiles, size, and which session uses each
382
- profile-delete <name> # Delete an idle named profile
383
- grant-permissions <perms> # Grant browser permissions
384
- ```
389
+ ### Network mocking
390
+
391
+ `route "<pattern>"` mocks matching requests (`--status`, `--body`,
392
+ `--content-type`, `--header`); `route-list` and `unroute` manage them, and
393
+ `network-state-set offline|online` simulates connectivity.
394
+
395
+ ### Passkeys (WebAuthn)
396
+
397
+ Run a `passkey-*` command, such as `passkey-list`, BEFORE the page calls
398
+ `navigator.credentials.create()` or `.get()`. The first one installs a virtual
399
+ authenticator in the session; until then the page gets Chrome's native OS
400
+ passkey dialog and the ceremony hangs. Then `passkey-list` shows what the page
401
+ registered, `passkey-add <rp-id>` seeds one, and `passkey-export` /
402
+ `passkey-import` keep passkeys across sessions (the export holds private keys).
403
+
404
+ ## Command reference
405
+
406
+ Every command, its flags and what it does. `patchright-cli <command> --help`
407
+ shows one command's flag defaults and examples; `patchright-cli` with no
408
+ arguments shows whether the daemon is up and which sessions are open.
409
+
410
+ <!-- BEGIN GENERATED: commands (scripts/gen_skill.py from COMMAND_SPECS; do not edit by hand) -->
411
+ ```bash
412
+ # Core
413
+ open [url] [--block-networks] [--headed] [--webmcp] # Open browser (starts daemon if needed)
414
+ attach --cdp=<url> [--cdp-headers] [--cdp-timeout] [--block-networks] # Attach to running Chrome via CDP
415
+ goto <url> # Navigate to URL
416
+ click <ref> [button] [--modifiers] [--scroll] # Click element
417
+ dblclick <ref> [button] [--modifiers] # Double-click element
418
+ fill <ref> <value> [--submit] # Fill text into element
419
+ type <text> [--submit] # Type text via keyboard
420
+ hover <ref> [--scroll] # Hover over element
421
+ select <ref> <value> # Select dropdown option
422
+ check <ref> [--scroll] # Check checkbox/radio
423
+ uncheck <ref> # Uncheck checkbox/radio
424
+ snapshot [ref] [--selector] [--filename] [--depth] [--interactive] [--boxes] # Take accessibility snapshot
425
+ find <text> [--regex] [--all] [--limit] [--role] [--name] [--description] [--exact] # Search the snapshot for matching elements
426
+ eval <expr> [ref] [--file] # Evaluate JavaScript (expression, --file or stdin)
427
+ text <ref|selector> # Get text content of element
428
+ html [ref] [--selector] [--include-shadow] [--filename] [--max-chars] # Print page HTML, or one element's outerHTML
429
+ screenshot [ref] [--full-page] [--hires] [--filename] # Save screenshot
430
+ drag <from> <to> [--scroll] # Drag element to target
431
+ drop <ref> [--path] [--data] # Drop file/data onto element (fails if it does not accept drops)
432
+ close # Close browser session (or the --tab it is addressed to)
433
+ detach # Detach attached session (keep external browser running)
434
+
435
+ # Navigation
436
+ go-back # Go back
437
+ go-forward # Go forward
438
+ reload # Reload page
439
+ url # Print current URL
440
+ title # Print page title
441
+
442
+ # Keyboard
443
+ press <key> # Press key
444
+ keydown <key> # Key down
445
+ keyup <key> # Key up
446
+
447
+ # Mouse
448
+ mousemove <x> <y> # Move mouse
449
+ mousedown [button] # Mouse button down
450
+ mouseup [button] # Mouse button up
451
+ mousewheel <dx> <dy> # Scroll mouse wheel
452
+
453
+ # Scroll & Wait
454
+ scroll <dx> <dy> # Scroll by pixel offset
455
+ scroll-to <ref> # Scroll element into view
456
+ wait [ms] [--url] # Wait for milliseconds, or for a URL
457
+ wait-for <ref> [--state] # Wait for element to reach a state
458
+
459
+ # Tabs
460
+ tab-list # List tabs
461
+ tab-new [url] # Open new tab
462
+ tab-close [index] # Close tab
463
+ tab-select <index> # Switch to tab (default tab only)
464
+
465
+ # Dialog
466
+ dialog-accept [text] # Accept next dialog
467
+ dialog-dismiss # Dismiss next dialog
468
+
469
+ # Upload/Resize
470
+ upload <file> [ref] # Upload file to input
471
+ resize <w> <h> # Resize viewport
472
+
473
+ # Emulation
474
+ set-color-scheme <dark|light|no-preference> # Emulate prefers-color-scheme
475
+ clear-color-scheme # Stop emulating prefers-color-scheme
476
+ set-reduced-motion <reduce|no-preference> # Emulate prefers-reduced-motion
477
+ clear-reduced-motion # Stop emulating prefers-reduced-motion
478
+ set-forced-colors <active|none> # Emulate forced-colors
479
+ clear-forced-colors # Stop emulating forced-colors
480
+ set-contrast <more|no-preference> # Emulate prefers-contrast
481
+ clear-contrast # Stop emulating prefers-contrast
482
+ set-media <screen|print> # Emulate CSS media type
483
+ clear-media # Stop emulating the CSS media type
484
+
485
+ # State
486
+ state-save [file] # Save cookies+storage to JSON
487
+ state-load <file> # Load saved state
488
+
489
+ # Storage
490
+ cookie-list [--domain] [--path] # List cookies
491
+ cookie-get <name> # Get cookie
492
+ cookie-set <name> <value> [--domain] [--path] [--expires] [--httpOnly] [--secure] [--sameSite] # Set cookie
493
+ cookie-delete <name> # Delete cookie
494
+ cookie-clear # Clear all cookies
495
+ cookie-import <file> # Import cookies from JSON
496
+ cookie-export [file] # Export cookies to JSON
497
+ localstorage-list # List localStorage
498
+ localstorage-get <key> # Get localStorage item
499
+ localstorage-set <key> <value> # Set localStorage item
500
+ localstorage-delete <key> # Delete localStorage item
501
+ localstorage-clear # Clear localStorage
502
+ sessionstorage-list # List sessionStorage
503
+ sessionstorage-get <key> # Get sessionStorage item
504
+ sessionstorage-set <key> <value> # Set sessionStorage item
505
+ sessionstorage-delete <key> # Delete sessionStorage item
506
+ sessionstorage-clear # Clear sessionStorage
507
+
508
+ # Passkeys
509
+ passkey-list [--rp-id] [--id] # List virtual passkeys; run before the page uses WebAuthn
510
+ passkey-add <rp-id> [--id] [--user-handle] [--private-key] [--public-key] [--sign-count] # Seed a virtual passkey
511
+ passkey-delete <id> # Delete a virtual passkey by credential id
512
+ passkey-clear [--rp-id] # Delete all virtual passkeys
513
+ passkey-export [file] [--rp-id] # Export virtual passkeys with private keys to an owner-only JSON
514
+ passkey-import <file> # Seed virtual passkeys from a passkey-export file
515
+
516
+ # Permissions
517
+ grant-permissions <perms> [--origin] # Grant comma-separated permissions
518
+
519
+ # Route
520
+ route <pattern> [--status] [--body] [--content-type] [--header] [--remove-header] # Mock requests matching a URL pattern
521
+ route-list # List active routes
522
+ unroute [pattern] # Remove route(s)
523
+ network-state-set <online|offline> # Set online/offline
524
+
525
+ # Code
526
+ run-code <code> [--file] # Run raw JS in page context (code, --file or stdin)
527
+
528
+ # Tracing
529
+ tracing-start # Start Playwright tracing
530
+ tracing-stop # Stop tracing and save
531
+
532
+ # Video
533
+ video-start [--fps] # Start video recording
534
+ video-stop [--filename] # Stop recording and save
535
+ video-chapter <title> # Add chapter marker to video
536
+ video-show-actions [--duration] [--position] # Annotate actions in the recording
537
+ video-hide-actions # Stop annotating actions
538
+
539
+ # PDF
540
+ pdf [--filename] # Save page as PDF
541
+
542
+ # DevTools
543
+ console [level] [--clear] # Start session-wide CDP capture and show messages; earlier messages are unavailable (detectable)
544
+ network [--static] [--clear] # Show network requests
545
+ requests [--static] [--clear] # Alias for `network`
546
+ request <id> [--body] # Show full detail for a network request
547
+ generate-locator <ref> # Emit Playwright locator expression for a ref
548
+ pick-locator [--detectable] [--wait] [--cancel] # Wait for a person to click an element; print its locator (page-detectable: needs --detectable)
549
+ highlight <ref> [--style] [--hide] # Show overlay on element (page-detectable while shown; removed on --hide)
550
+
551
+ # Debugger
552
+ debugger-pause # Pause before the next page action, navigation or eval; that command replies at once, held
553
+ debugger-step # Run the paused call and pause before the next one; prints the held command's result
554
+ debugger-resume # Let the held command finish and print its result (or cancel an unhit pause)
555
+ debugger-status # Show the debugger state: off, armed, or the paused call and held command
556
+
557
+ # WebMCP
558
+ webmcp-list # List the WebMCP tools the page registers
559
+ webmcp-call <name> [json] [--params] # Call a WebMCP tool the page registers
560
+
561
+ # Session
562
+ list # List sessions
563
+ close-all # Close all sessions
564
+ kill-all [--force] # Kill all sessions and stop the daemon
565
+ delete-data # Delete this session's profile
566
+
567
+ # Profiles
568
+ profile-list # List profiles, their size and which session uses them
569
+ profile-delete <name> # Delete a named profile
570
+
571
+ # Dashboard
572
+ show [--annotate] [--wait] [--no-open] # Open session dashboard
573
+
574
+ # Codegen
575
+ codegen [file] # Start recording interactions
576
+ codegen-stop [file] # Stop recording and save script
577
+
578
+ # Setup
579
+ install --skills | --hooks [--uninstall] # Install agent skill files, or session-start hooks
580
+ mcp [--http] [--host=HOST] [--port=N] # Start MCP server (stdio by default)
581
+ daemon-info --json # Show daemon client protocol and token path without starting it
582
+ ```
583
+ <!-- END GENERATED -->
385
584
 
386
585
  ---
387
586
 
@@ -2,97 +2,108 @@
2
2
 
3
3
  ## How the snapshot system works
4
4
 
5
- patchright-cli uses Playwright's accessibility tree to build a YAML snapshot of all interactive elements on the page. Each element gets a short ref like `e1`, `e5`, `e12`. You use these refs to target elements in commands like `click`, `fill`, `hover`, etc.
5
+ patchright-cli takes Playwright's AI-mode accessibility snapshot of the whole
6
+ page, iframes included, and saves it as YAML. Elements carry Playwright's own
7
+ refs, like `e5` or `f3e5`. You use these refs to target elements in commands
8
+ like `click`, `fill`, `hover`, etc.
6
9
 
7
10
  ```
8
11
  open browser -> snapshot -> read refs -> interact -> snapshot again -> repeat
9
12
  ```
10
13
 
11
- Refs are **ephemeral** -- they change every time the page updates. After navigation, form submission, or any dynamic content change, you must re-snapshot to get fresh refs.
14
+ ## What a ref is
15
+
16
+ - A ref names **one element** for as long as that element stays on the page.
17
+ Taking another snapshot, or acting, does not renumber it; new elements get
18
+ new numbers.
19
+ - `e5` is an element of the tab's first page. After a navigation (`goto`, a
20
+ link, `reload`) the page's refs gain a frame prefix, `f3e5`, and refs inside
21
+ an iframe always have one. Copy refs exactly as printed.
22
+ - A ref whose element was removed or replaced fails at once:
23
+ `Ref e7 no longer matches an element (removed or changed since the snapshot). Run snapshot.`
24
+ A ref from a page the tab has left fails with `is from a page this tab has left`.
25
+ Nothing falls back to "an element with the same role and name", so a stale
26
+ ref never clicks the wrong element.
27
+ - Refs are **per tab**. A ref that is not in this tab's last snapshot is refused:
28
+ `e2 is not from a snapshot of this tab; run snapshot (...)`. An element whose role
29
+ or name changes (a button relabelled "Saved") gets a new ref, so the old one is refused too.
30
+ After `tab-select`, use the snapshot it prints. A click that opens a popup makes
31
+ the popup current, and the popup's first-document refs (`e1`, `e2`, ...) can reuse
32
+ numbers from the opener, so use the snapshot printed after the click.
33
+ - `e5`, `@e5`, `ref=e5` and `[ref=e5]` all work. Anything else is a usage error (exit 2).
12
34
 
13
35
  ## Snapshot commands
14
36
 
15
37
  ```bash
16
38
  patchright-cli snapshot # Full page snapshot
17
39
  patchright-cli snapshot e3 # Subtree rooted at ref e3
18
- patchright-cli snapshot --depth=2 # Limit tree depth (reduces noise)
40
+ patchright-cli snapshot --selector="#main" # Subtree under a CSS selector (exactly one match)
41
+ patchright-cli snapshot --depth=2 # Levels 0..2 only
42
+ patchright-cli snapshot -i # Interactive elements only
43
+ patchright-cli snapshot --boxes # [box=x,y,w,h] on each element
19
44
  patchright-cli snapshot --filename=snap.yml # Save to custom filename
20
- patchright-cli snapshot -i # Interactive-only elements
21
- patchright-cli snapshot --interactive # Same as -i
22
45
  ```
23
46
 
24
- ### Options
25
-
26
47
  | Flag | Effect |
27
48
  |------|--------|
28
49
  | `[ref]` | Show only the subtree rooted at the given ref |
29
- | `--selector=<css>` | Show only the subtree under a CSS selector. Must match exactly one element |
30
- | `--depth=N` | Limit depth of the tree (useful for complex pages) |
31
- | `-i` / `--interactive` | Show only interactive elements (buttons, links, inputs) |
50
+ | `--selector=<css>` | Show only the subtree under a CSS selector. Must match exactly one element that is in the accessibility tree |
51
+ | `--depth=N` | Show levels 0..N. A node whose children were cut ends in `# +N refs` (or `# +more`) |
52
+ | `-i` / `--interactive` | Interactive elements, clickable `generic [cursor=pointer]` nodes, a combobox's options, and the named landmarks and iframes around them. `text:` and `/url:` lines are dropped |
53
+ | `--boxes` | Append `[box=x,y,w,h]`: viewport coordinates in CSS pixels, converted to page coordinates inside iframes |
32
54
  | `--filename=F` | Save snapshot to a custom file path |
33
55
 
34
- ## When to re-snapshot
35
-
36
- Re-snapshot whenever the page state has changed and you need to interact with elements:
56
+ Every view is cut from one full-page snapshot, so the refs it shows are the
57
+ page's refs: a ref from `snapshot e3`, `--depth` or `-i` works with every
58
+ command, and refs outside the printed part keep working too.
37
59
 
38
- - After `goto`, `go-back`, `go-forward`, `reload`
39
- - After `click` that triggers navigation or DOM changes
40
- - After form submission
41
- - After `wait` / `wait-for` for dynamic content
42
- - After `eval` / `run-code` that modifies the DOM
60
+ ## When to re-snapshot
43
61
 
44
- Most state-changing commands (click, fill, goto, etc.) **auto-snapshot** and return the new snapshot. You only need to manually run `snapshot` when the page changes asynchronously or you need a subtree/filtered view.
62
+ Most state-changing commands (click, fill, goto, etc.) **auto-snapshot** and
63
+ return the new snapshot. Re-snapshot yourself when the page changes on its own
64
+ (timers, AJAX), after `eval` / `run-code` that changes the DOM, or when a ref
65
+ reports `no longer matches an element`.
45
66
 
46
67
  ## Reading the snapshot
47
68
 
48
- The snapshot is a YAML tree. Each element shows:
49
- - Its **ref** (e.g., `e5`)
50
- - Its **role** (button, link, textbox, heading, etc.)
51
- - Its **name** or text content
52
- - Child elements nested underneath
53
-
54
- Example output:
55
69
  ```yaml
56
- - heading "Welcome" [e1]
57
- - link "Sign in" [e2]
58
- - navigation [e3]
59
- - link "Home" [e4]
60
- - link "About" [e5]
61
- - main [e6]
62
- - textbox "Search" [e7]
63
- - button "Go" [e8]
70
+ - heading "Welcome" [level=1] [ref=e2]
71
+ - navigation "Main" [ref=e3]:
72
+ - link "Home" [ref=e4]:
73
+ - /url: /
74
+ - main [ref=e6]:
75
+ - textbox "Search" [ref=e7]
76
+ - button "Go" [ref=e8]
77
+ - generic [ref=e9] [cursor=pointer]: Open card
78
+ - combobox "Size" [ref=e10]:
79
+ - option "Small" [selected]
80
+ - option "Large"
81
+ - iframe [ref=e11]:
82
+ - button "Pay" [ref=f2e4]
64
83
  ```
65
84
 
66
- ## Troubleshooting
85
+ - `[active]` marks the focused element, `[cursor=pointer]` a node that looks
86
+ clickable though its role does not say so.
87
+ - Wrapper `generic` nodes with nothing of their own are not printed; their
88
+ children move up a level.
89
+ - `text:` lines and `option`s have no ref. Select an option by its label:
90
+ `select e10 Large`.
67
91
 
68
- ### "Could not locate element for ref"
69
- The page has changed since the last snapshot. Run `snapshot` to get fresh refs and retry.
92
+ ## Troubleshooting
70
93
 
71
94
  ### Element not visible or not interactive
72
- Some elements are hidden or overlapped. Try:
73
95
  - `scroll-to <ref>` to bring the element into view
74
- - `wait-for <ref>` to wait until the element appears
75
- - `snapshot -i` to see only interactive elements
76
- - `snapshot <ref>` to inspect a subtree for nested elements
77
- - `snapshot --selector="#main"` to scope by CSS when you have no ref yet
78
-
79
- ### Refs from a scoped snapshot
80
-
81
- A scoped snapshot -- `snapshot <ref>` or `snapshot --selector=<css>` -- numbers
82
- its refs from `e1` within that subtree, and those refs resolve inside the same
83
- subtree. They are not the numbers a full-page `snapshot` would give, so do not
84
- mix refs from a scoped snapshot with refs from a full one: take a fresh
85
- snapshot at the scope you intend to work in.
96
+ - `wait-for <ref>` to wait until it is visible (`--state=hidden` to wait until it goes)
97
+ - `snapshot <ref>` to inspect a subtree
86
98
 
87
99
  ### Too many elements in snapshot
88
- Use `--depth=N` to limit tree depth, or snapshot a specific subtree with `snapshot <ref>`. The `-i` flag also helps by filtering to interactive elements only.
100
+ Use `find`, `--depth=N`, `-i`, or `snapshot <ref>`.
89
101
 
90
- ### Stale refs after dynamic content
91
- SPAs and pages with AJAX calls update the DOM without navigation. After triggering dynamic content (e.g., clicking a "Load more" button), wait briefly and re-snapshot:
102
+ ### Elements that appear later
92
103
  ```bash
93
- patchright-cli click e5 # Triggers dynamic load
104
+ patchright-cli click e5 # Triggers a dynamic load
94
105
  patchright-cli wait 1000 # Wait for content
95
- patchright-cli snapshot # Get fresh refs
106
+ patchright-cli snapshot # Refs for the new elements
96
107
  ```
97
108
 
98
109
  ## `find` — searching the snapshot
@@ -103,14 +114,15 @@ find --regex <pattern> Regex match; bare patterns are case-insensitive
103
114
  find --regex "/p/ims" Slash form; supported flags are i, m, s
104
115
  find --all Search every node, not just interactive roles + heading
105
116
  find --limit=N Cap rendered hits (default 20)
117
+ find --role=<role> Elements get_by_role matches (--name, --description, --exact)
106
118
  ```
107
119
 
108
120
  ### What gets searched
109
121
 
110
- By default, roles in `SEARCHABLE_ROLES` — every interactive role plus
111
- `heading`. This is deliberate: role filtering is the single biggest lever on
112
- output size. Measured across 13 queries on four real pages it cut hits 4.3x
113
- (729 to 168); on one Wikipedia query, 442 hits became 53.
122
+ By default, every interactive role plus `heading`. This is deliberate: role
123
+ filtering is the single biggest lever on output size. Measured across 13
124
+ queries on four real pages it cut hits 4.3x (729 to 168); on one Wikipedia
125
+ query, 442 hits became 53.
114
126
 
115
127
  Matching runs against a node's accessible name. For unnamed nodes such as
116
128
  `- text: Star 95.3k`, the value after the colon is used instead. Property
@@ -120,7 +132,8 @@ lines like `- /url: ...` are not nodes and never match.
120
132
 
121
133
  Per hit: a ` # ancestor > ancestor > parent` breadcrumb (3 deep, names cut at
122
134
  45 characters, repeated names collapsed), then the matched node with its ref,
123
- then its subtree.
135
+ then its subtree. A hit without a ref of its own (an `option`, or a `text:`
136
+ line under `--all`) shows the nearest element you can act on as `[in=e12]`.
124
137
 
125
138
  `find` prints inline and writes no `.yml` file. `snapshot` still writes one.
126
139
 
@@ -80,7 +80,7 @@ patchright-cli state-save auth.json # Save cookies + localSt
80
80
  patchright-cli state-load auth.json # Restore state
81
81
  ```
82
82
 
83
- When loading state, navigate to the matching origin first so localStorage can be applied correctly.
83
+ `state-load` replaces the session's state: it first clears the existing cookies, localStorage, IndexedDB and OPFS data, then applies the file. localStorage is applied to every origin in the file; you do not need to visit an origin first.
84
84
 
85
85
  ## Cookie persistence login pattern
86
86