Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

How navigera works

The three ways to run navigera; what it does between commands: waits, settling, tabs, dialogs.

navigera drives a real Chrome over the DevTools Protocol from one native binary. There are three ways to run it:

modehowfor
sessionnavigera -s <name> start, then one command per process, then quitagents’ shell tools, people at a terminal
servenavigera serve; JSON commands on stdin, one JSON response per lineprograms holding a pipe open
one-shotnavigera <command> …a single action (launches and closes a browser)

The agent-oriented guide is the skill, also printed by navigera skill. This page is the full reference.

Behaviour

  • Snapshots wait for fetched data. Before ax and screenshot, navigera waits until the tab has had no fetch/XHR in flight for 500 ms (the usual network-idle window), at most 3 s; requests open longer than 5 s (long polls, streams) don’t count. A page that has been quiet, as it usually is while an agent thinks, is read at once. So goto … && … ax shows a single-page app’s list, not its “Loading…” placeholder. A request to a URL the page has already fetched twice at a steady interval is a poll and doesn’t count, so a dashboard that refreshes every few hundred milliseconds is read at once. After an action whose own requests have started (a click that fetches), the snapshot waits for those requests and 100 ms more, not the whole window: a click that loads data for 200 ms is read about 300 ms later, with the data. A window set with set network-quiet <ms> holds after actions too. --no-wait (on ax, screenshot and ax --grep) skips the wait.
  • Clicks are trusted mouse events at the element’s centre after scrolling it into view, once the element has stopped moving: CSS animations and transitions running on it or an ancestor (a dialog sliding in) finish first, as a user waits for them, and pages often wire a dialog’s buttons only once it has opened. With nothing animating this costs nothing. navigera checks that the press reached the page: Chrome occasionally acknowledges mouse events it never delivers (seen right after a tab switch), and then the click is sent once more, or as DOM events if it still doesn’t arrive (synthetic_click says so). Same-origin iframe offsets are added in the page; inside a cross-origin iframe (refs only) the box comes from DOM.getContentQuads.
    • A styled checkbox or radio (the <input> hidden or covered by its own label’s box) is clicked through its label, as a user would.
    • An element that never holds still (a perpetual drift) gets a second in all to stop, then is clicked where it was last read.
    • If something else covers the element’s centre (a toast, a sticky header, an overlay), the element is tried at the edges of the viewport, then the click waits for the cover to go (up to the element wait). If it stays covered the click fails and names the covering element and its controls: a user would have clicked that instead. A cover that stays put with controls of its own (a cookie banner, a dialog) is reported after a second, unless the page is still fetching (a loading overlay with a Cancel button goes when its data arrives). click --force sends DOM events to the element regardless (synthetic_click). fill likewise scrolls a field out from under a panel before setting it.
    • A disabled control is waited for (up to the element wait) and then refused; fill does the same for a disabled or read-only field.
    • An element a user can’t see where it is (zero size, clipped, or under its own wrapper, like the real input of a styled radio card) fails at once, naming what a click there would hit and, where there is one, what stands for it (its label, or the clickable card around it). --force sends DOM events to it.
    • If the click starts a navigation, the command returns once the new document is parsed.
    • A click that changes nothing says so. From just before the press, navigera watches the page’s DOM (the document, the element’s frame and every open shadow root), events a DOM observer can’t see (input, change, submit, toggle, invalid, copy, a scroll, a navigation starting), clipboard writes, focus moving elsewhere, form values and the URL a script set, and what only the browser sees (navigations, dialogs, new tabs, downloads, requests). The first sign ends the watch, usually within the round trip that already checked delivery. Requests that are the page reporting on itself don’t count: beacons and well-known analytics services are ignored, and a first-party request that reads like reporting (/event/…, /collect, /log) is waited for (up to 1.5 s) and judged by what the page does with the answer. With nothing after 200 ms (or after that answer), the result carries no_effect, naming any reporting requests: often a control the page hasn’t wired up yet, so check for what the click should do before clicking again. Clicks on fields, <select>s and right or middle clicks aren’t judged, nor pages with same-origin frames it doesn’t watch. NAVIGERA_TRACE_EFFECT=1 on start adds an effect_trace to click results (what was seen).
    • A click before the page wired the element up is sent again. On a page whose document started loading less than 10 s ago, the click also counts what listens for it (click, mouse, pointer and touch listeners, handlers set as properties or attributes included, navigera’s own left out) on the element, its ancestors, its document and its window. When nothing did and the click changed nothing, no script of the page ran for it: navigera watches the page while it has scripts or data requests in flight, and until 500 ms after the click without any (never past the element wait, at most 5 s), and if the page adds such a listener there (a script after load, hydration of a container or of the whole document), it clicks once more; the result carries clicked_again with how long the page took. A click anything heard is never sent again: analytics on the document, or a script that records early clicks to replay them once the page is wired, may act on it later where navigera can’t see. A dead button on a page that just loaded reports no_effect about 300 ms later than before. Not covered: a page that listens on the document from the start (no_effect as before), an element inside a frame, a handler wired more than 500 ms after the click with nothing loading.
    • A click the page moved away from says so. A page that answers the press itself, by moving the element (a banner put in above it on pointerdown) or replacing it (a button rendered anew on mousedown), has the release land elsewhere: the click event goes to the parent the press and the release share, or the browser sends none, and the element’s own handler never runs. The result carries click_missed with where the click went. The page saw the press, so navigera doesn’t press again: check what the click should do first.
  • Page errors are reported. An uncaught exception while a command ran adds one line to its notes (the page threw TypeError: …; \errors` lists them), so a click whose handler crashed doesn't look like a click that did nothing. console, errorsandnetwork` keep the last 1000 entries per tab.
  • A page replaced mid-op: when a navigation replaces the page while an op is still looking for its element (a step that saves with a request and only then reloads, a client-side redirect), the op looks again on the new page within its wait.
  • Navigation settling: every command that reads or acts on the page first waits for any navigation an earlier action started, such as a JS redirect, so it never reads the previous page. The wait is bounded by the op’s own timeout_ms and never fails the op. Once the new document has committed, it waits at most 5 s for DOMContentLoaded: a page that keeps streaming is then used as it is, and the response says "loading": true.
  • Paths (upload, screenshot) given to a session client are resolved in the caller’s working directory, not the session server’s.
  • New tabs: pages opened with target=_blank or window.open are adopted into the tab list and become active. Tabs the page closes are dropped.
  • Dialogs are answered the moment they open: accept by default, or dismiss after dialog --dismiss. A beforeunload dialog is always accepted. Each dialog is reported in the response.
  • No Runtime.enable: it is the best-known automation fingerprint, and nothing here needs it.
  • Logs: launch details go to stderr only with NAVIGERA_VERBOSE=1.

Made from docs/navigera.md.