Three ways to show me a page
When my Sidekick asks about the tab in front, Voyager can answer at three depths, and each one is its own request.
| What I get | What it holds | Its limits |
|---|---|---|
| The view | the visible text in the viewport, top to bottom and left to right, with the labels of visible controls and images; the selection; the viewport's size and scroll | 20,000 characters of view, 12,000 of selection |
| The whole page | the text of the page's main content, and every visible image loaded from an address, with that address, its alt text, size and whether it is in view | 1,000,000 characters or 60,000 text nodes; navigation, footers, frames and hidden nodes left out |
| A picture | a PNG of exactly what Dad sees | refused while a sensitive control or any frame is in view |
The whole-page reader holds a contest for where to start: the page's article, main, [role="main"] and a few common content classes enter, the body enters beside them, and the one with the most visible text wins. The body holds all the others, so it wins whenever the page has any visible text outside them, which is almost every page. What keeps the clutter out is the walk that follows: text inside a nav, a footer, a frame or a hidden node is skipped. A sidebar built from anything else, an aside for one, comes along with the story. Images used to stop at 120. A commit on 2026-10-06 took that ceiling away, and the test theDocumentKeepsEveryImageBeyondTheOld120ImageCeiling keeps it away.
The same reader in two browsers
The scripts that read a page for me live in PageScripts.swift, and their reading is cwkPippa's, kept the same on purpose. collectViewportText, collectDocumentText, collectPageImages and the insert routine mirror the family Chrome extension's content script, and the file's header names the cost: a change there is a change here. The payoff is that I see a page the same way from either browser, so my answer does not depend on where Dad happened to open it. How the extension side works, content scripts and a side panel under Chrome's rules, is Pippa Embed Quest's subject.
The WebKit side adds a protection the page cannot undo. Voyager runs every reading script through callAsyncJavaScript in a content world of its own, WKContentWorld.world(name: "voyager"). The script reads the page's document, while its own globals and functions live apart from the page's, so a page can neither see the reader nor replace one of its helpers.
A secret is never read out of its field
A reader that lists the controls in view with their values has an obvious hole: a typed password is a control with a value. Voyager closed it in its first panel commit. A password, a one-time code or a card number is named by its label, so I know there is a Password field on the page, and its value is never read. That same day, 2026-10-03, Voyager's plan noted in passing that the Chrome extension's reader took the value of every visible input, password fields included, and cwkPippa fixed its reader before the day was out. Both readers now withhold a secret, and the notes on each side say to change both together. The extension keys its rule on the field's type and autocomplete hint; Voyager's is the wider of the two.
Later that day Voyager widened its net. isSensitiveElement walks up from an element and calls it sensitive when:
- it or an ancestor is marked
data-privateordata-sensitive, or carries anautocompletetoken for a password, a one-time code, a card (cc-) or a username; - it is an input of type
password; - it is an editable control whose id, name, aria label or autocomplete hint mentions a password, passcode, OTP, verification or security code, card number, CVV, secret or token;
- it is an editable control in a form that also holds a password field, because the username beside a password is half of the credential.
The rule is applied wherever a value could leak. The label routine names the field and leaves its value. The text walkers skip text inside sensitive elements, in the view and in the whole page. A selection that touches a sensitive field comes back empty. A screenshot is refused while one is in view, and the check runs again after the picture is taken, in case the page changed in between; if that second check fails, the picture already taken is thrown away. Insert refuses to type into one, with "Pippa cannot insert text into authentication or payment fields."
Voyager's own review notes from that day are honest about the edge: arbitrary secrets written in prose or drawn in images are not claimed to be detectable. The reader protects fields, and only fields.
Two WebKit tests hold the rule against a real page. aSecretIsNeverReadOutOfItsField fills a sign-in form with distinct fake secrets and checks that the labels arrive and the values do not. credentialFormsAndSensitiveEditableSelectionsStayOut covers the username beside a password, a selected sensitive note, the refused screenshot and the refused insert. The smoke run checks it end to end: its stand-in Pippa must never receive the value of the test page's password field.