Skip to content

page-as-data

Use it inside your own browser tooling

The part that runs in the page is one file, page-as-data.js. Inject it before the page's own scripts, so it can see router requests from the start, and call window.__pageAsData.

// Playwright
import { readFileSync } from 'node:fs'
import { createRequire } from 'node:module'
const inPage = readFileSync(createRequire(import.meta.url).resolve('@keenskills/page-as-data/in-page'), 'utf8')
await page.addInitScript(inPage)
await page.goto('http://localhost:3000/orders')
await page.evaluate(() => window.__pageAsData.settle())
const screen = await page.evaluate(() => window.__pageAsData.read())
const issues = await page.evaluate(() => window.__pageAsData.layoutIssues())

With Chrome DevTools MCP, pass the file's contents as initScript to navigate_page, then call the same functions with evaluate_script. You can also paste the file into the DevTools console.

Function Returns
await settle({ timeoutMs }) { settled, ms }, or why it did not settle
read({ maxText, maxRows }) url, title, headings, dialogs, alerts, text, tables, form, controls, images
inspect(query) For each match: box, visible, why hidden or cut off, colours, contrast, readable
layoutIssues() page overflow, clipped controls, sticky that cannot stick, small targets
await click(name) / await fill(label, value) What it acted on, then settles

It reads the page and nothing else. It makes no network calls of its own, and it only wraps window.fetch to count React Server Component requests. It never changes them. Password fields are reported as ••••, never their value.

From Node, import { readPage, checkPages } from '@keenskills/page-as-data' returns the same results as the CLI's --json.