uisnap - UI state snapshot for coding agents

Pulling in the full DOM and console logs is not a good use of tokens. Capture the browser state once, then let your agent write queries against it.

npm install -g uisnap
npx playwright install chromium
uisnap setup-skill  # optional: installs Claude Code skill

Requires Node.js 18, 20, or 22 LTS

The package offers two sets of commands: capture commands and analyze commands.

Capture Commands

Sample Script

// my-script.js - Test a login flow
await page.goto(args[0] || 'https://myapp.com/login');

await utils.captureStep(page, 'initial', async () => {
  // State captured after page loads
});

await utils.captureStep(page, 'fill-form', async () => {
  await page.fill('input[name="email"]', '[email protected]');
  await page.fill('input[name="password"]', 'password123');
});

await utils.captureStep(page, 'submit', async () => {
  await page.click('button[type="submit"]');
  await page.waitForURL('**/dashboard');
});

Captured data is stored in timestamped snapshot directories for later analysis.

Analyze Commands

Why?

Context efficiency, basically. I got tired of copying from the console. Tried Playwright MCP, which worked great, but super wasteful on tokens. Why read the whole thing when the agent can grep/jq or write SQL?

Manual


User: There was an error.

Agent: What's the stack trace?
User: [copies stack trace from browser]

Agent: Can you check if analytics.js loaded?
User: [checks Network tab, reports back]

Agent: What's the order of script tags?
User: [inspects DOM, copies HTML]

→ User is stuck in the loop, manually gathering data.

Playwright MCP

User: "Fix the console errors on myapp.com"

Agent: Let me fetch the page...
  → Loads full DOM (15,000 tokens)
  → Parses all console logs (8,000 tokens)
  → Analyzes network tab (5,000 tokens)

  ... that's a lot of tokens

With uisnap

User: "Fix the console errors on myapp.com"

Agent: Capturing page state...
  $ uisnap snapshot https://myapp.com
  $ uisnap analyze-console .uisnap/myapp.com/latest/console.jsonl

→ Agent sees: ERR_BLOCKED_BY_CLIENT in tracker.js

Agent: Let me check the script load order...
  $ grep -A5 "tracker.js" .uisnap/myapp.com/latest/network.jsonl

Agent: And find the analytics script tag...
  $ grep "analytics" .uisnap/myapp.com/latest/a11y.yaml

Agent: Found the issue. Script order is wrong.
  [Makes edit to index.html]

Agent: Verifying the fix...
  $ uisnap snapshot https://myapp.com
  $ uisnap analyze-console .uisnap/myapp.com/latest/console.jsonl


→ Agent used grep/jq/CLI tools autonomously
→ Each query: ~200 tokens (local files)
→ Total: ~2,000 tokens

Claude Code Skill

Install the skill to teach Claude Code when and how to use uisnap automatically.

Installation

uisnap setup-skill          # project-level (recommended)
uisnap setup-skill --global # user-level

Activation

Once installed, Claude automatically uses uisnap when you mention:

  • "Debug console errors on https://myapp.com"
  • "Help me test the login flow"
  • "Why is the submit button not working?"
  • "Page is slow/laggy"
  • "Check network requests on this page"

Decision Tree

Functional issues? → Snapshot workflow
  Button doesn't work, form fails, console errors, API 404s

Performance issues? → Trace workflow
  Page slow, scrolling janky, animations stutter, UI freezes

Not sure? → Start with snapshot, escalate to trace if needed

Key Features

  • 17x token reduction - Capture once, query many times
  • Auto-organized snapshots - Timestamped directories, never overwrites
  • Multi-step flows - JavaScript with captureStep helper
  • Local analysis - Fast grep/SQL queries on captured state

Script API Reference

Scripts run in an async context with access to Playwright and these helpers:

Playwright Objects

  • page - Playwright Page instance (docs)
  • context - Browser context for CDP access, cookies, etc.
  • browser - Browser instance
  • args - Remaining CLI arguments after URL
  • fs, path - Node.js modules

Capture Helpers (utils.*)

  • captureStep(page, name, action?) Capture accessibility tree + metadata after action. Creates step-N-{name}/ directory.
  • startChromeTrace(cdp) Start Chrome DevTools performance trace. Use with context.newCDPSession(page).
  • stopChromeTraceAndImport(cdp, path) Stop trace and import to DuckDB. Returns .db path for SQL queries.

File Helpers (utils.*)

  • writeJson(filepath, data) Write JSON with formatting
  • writeJsonl(filepath, items) Write array as newline-delimited JSON
  • appendJsonl(filepath, item) Append single item to JSONL file
  • baseOutputDir Auto-generated output directory path