Skip to content
SkilledDragonEngineering Intelligence
AI DropKeylessOctober 20, 2026

Playwright innerText drops hidden notes. White-on-white text still gets through.

We read a help page with five hidden notes through Playwright in Chrome. innerText kept none of them, but it kept four of five notes hidden with styling tricks. findInvisible flags those four.

By David Discua

Measured in the lab

19/19
tests passed
0
hidden notes in innerText
4/5
styled tricks kept
11693 ms
test run
page.content() HTMLcomment included5
textContentclass, style, hidden, JSON4
innerTextrendered text only0
  • innerText of the help page has 0 hidden notes
  • textContent of the same page has 4
  • innerText keeps 4 of 5 styled tricks
  • findInvisible flags all 4 and the CLI exits 3
  • every request outside local fixtures is aborted

From reports/gate.json · run on October 20, 2026. bun test on Linux with playwright-core 1.64.1 (cfe490d941f9), Google Chrome 155.0.8059.84 and Bun 1.4.2; GitHub Actions has not run yet

How it is wired

renderstextchecksexit 3Tricks page5 styled notesinnerTextkeeps 4 of 5findInvisibleflags 4 tricksAI modelreads 4 notes

01/03A test page hides five notes behind styling tricks.

Playwright's locator.innerText() returns the text Chrome renders, so an agent that browses with Playwright can use it to turn a page into text for a model. We hid five notes in a help page (a stylesheet class, an inline display:none, the hidden attribute, an HTML comment and a JSON script block), and innerText returned none of them while textContent returned four and the raw HTML from page.content() carried all five. The catch is styling: on a second page, innerText kept four of five notes that a person cannot read.

Each note tells an assistant not to recommend a data protection authority, on a page about deleting an account.

The catch

innerText follows rendering, and rendered text can still be unreadable. On a second page we hid five more notes with styling alone:

TrickCSSIn innerTextFlagged by findInvisible
White on whitecolor:#fff on a white bodyyessame-color
Transparentopacity:0yesopacity-zero
Zero sizefont-size:0yesfont-size-zero
Off-screenposition:absolute;left:-9999pxyesoff-screen
Not visiblevisibility:hiddennonot needed

innerText kept four of the five. A person looking at the page sees none of them, and a model reading the innerText gets all four. The lab's findInvisible walks the rendered elements, compares text color with the nearest background, checks opacity up the tree, font size and the element's box, and flags all four. The CLI exits with code 3 when it finds one. It only knows these four tricks and only looks at the lab's tagged notes. innerText is a rendering filter, so keep your own prompt-injection defenses in place.

What we ran (keyless)

git clone https://github.com/SkilledDragonCorp/oculto-playwright-innertext.git
cd oculto-playwright-innertext
bun install
bun run src/cli.ts fixtures/ayuda.html
bun run src/cli.ts fixtures/trucos.html
bun test

From reports/gate.json, run on October 20, 2026 on Linux:

FieldValue
Pinplaywright-core@1.64.1, tag v1.64.1
BrowserGoogle Chrome 155.0.8059.84
RuntimeBun 1.4.2
Tests19 passed, 0 failed, exit 0
Duration11,693 ms

The help page run exits 0 and prints innerText notes: 0 and textContent notes: 4. The tricks page run exits 3 and lists the four flagged notes. GitHub Actions has not run on this repo yet. On macOS the same bun test passed 17 and failed 2, because the two network-isolation tests need unshare, which macOS does not have.

How it is wired

The lab launches Chrome through playwright-core and reads only local HTML fixtures. Service workers are blocked, and routing sits on the browser context, because the pinned Playwright docs say a bare page.route misses requests a service worker intercepts and the first request of a popup. Every request outside the fixtures folder, the temp dir and the local fixture server is aborted, and WebSocket handshakes are closed. A control test keeps the bare page.route path and runs it with no network, so you can see the popup request it misses. No step reads an API key.

Minilab (open source)

Upstream is microsoft/playwright (98,181 stars, Apache-2.0, TypeScript, as of October 20, 2026). To try a trick we did not cover, add a paragraph with a TRUCO- tag to fixtures/trucos.html, run bun run src/cli.ts fixtures/trucos.html, and see whether innerText keeps it and findInvisible flags it. The repo also ships a visible-text skill in .claude/skills/ for Claude Code and Cursor.

Run it yourself

SkilledDragonCorp/oculto-playwright-innertext

Clone, install and run the report with no API keys. The numbers above are what that run writes.

bun install && bun run src/cli.ts fixtures/ayuda.html

SkilledDragon is not affiliated with Microsoft or the Playwright project. Numbers are from our own keyless Linux lab run; GitHub Actions has not run yet. Re-run bun test before relying on them. Marks belong to their owners.

All labs