Skip to content
Back to skills

Ux Visual Persona Crawl

ASecurity

Create a panel of synthetic personas with demographics, then have each one crawl a website purely by sight, from screenshots, clicking by screen position the way a person does, with no reading of page text, HTML, accessibility tree or other metadata. Records every persona's navigation as JSON, collects in-the-moment reactions and an exit interview, and produces a report of flow bottlenecks, friction points, contradictions, UI and UX problems, unclear or hidden buttons, and measured colour con...

  • 3 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added November 13, 2026
datapythongobashreact

Works with

  • cli

Security analysis

A100/100

Pro scans all 20 files and shows the line behind each finding

Scanned November 13, 2026

npx -y skills add raghuramsirigiri/raghuram-skills --skill ux-visual-persona-crawl --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ux Visual Persona Crawl?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ux Visual Persona Crawl
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/raghuramsirigiri-ux-visual-persona-crawl/badge)](https://www.skillsdirectory.com/skills/raghuramsirigiri-ux-visual-persona-crawl)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ux-visual-persona-crawl
description: Create a panel of synthetic personas with demographics, then have each one crawl a website purely by sight, from screenshots, clicking by screen position the way a person does, with no reading of page text, HTML, accessibility tree or other metadata. Records every persona's navigation as JSON, collects in-the-moment reactions and an exit interview, and produces a report of flow bottlenecks, friction points, contradictions, UI and UX problems, unclear or hidden buttons, and measured colour contrast, each backed by a screenshot. Use this whenever someone wants synthetic users, a simulated usability test, persona walkthroughs, a visual or "human-eye" UX audit, a heuristic review of a sign-up, checkout or onboarding flow, or wants to know where people would get stuck, confused or drop off on a site, even if they only say "walk through our site like a customer", "where do users struggle on this page", "check our signup flow for UX issues" or "test this staging site with a few personas".
---

# UX visual persona crawl

Build a panel of distinct people, let each one use a site **with their eyes only**, then have a separate reviewer turn the recordings into findings that each point at a screenshot.

Four ideas shape everything here:

- **Pixels in, positions out.** A person never sees the HTML. They see a screen, read what is drawn, and click where something looks clickable. So the persona gets screenshots and the address bar, nothing else, and acts by x,y position. Problems that exist only visually, such as a call to action that looks disabled, text too faint to read, a fee in grey fine print, or a button that does nothing when pressed, surface only this way. A crawler that reads the markup sees the label "See plans" and clicks it without ever noticing that it is barely visible. `scripts/eyes.py` enforces this: it never reads the page, it only screenshots it.
- **The persona and the reviewer are different agents.** Someone trying to get something done notices different things from someone paid to critique. Mixing them produces polite, generic critique.
- **The numbers come from the recording.** Flow metrics are computed by `scripts/report.py` from each persona's `journey.json`. Contrast is measured from screenshot pixels by `eyes.py measure`, not estimated by eye. Every finding must cite a session, step and box on that step's screenshot, and `report.py verify` removes any that don't hold.
- **Simulated people point at where to look.** They don't tell you how many customers would leave. The report says so, and turns its strongest findings into questions for real users.

## Limits to keep

These exist for reasons that don't change with the request.

- **Live sites are read-only.** In `observe_only` (the default), the driver blocks every request that would send data (POST, PUT and so on) and refuses typing except short search words. Putting invented details into a real company's forms can be a false statement to them, and real details aren't ours to use. Personas stop at the first form and say what they would do.
- **Typing and submitting forms happen only on a test system** (`test_env`), which the driver allows only on local or staging-style hosts, with test values from the study file. Don't relabel a production host to get past this.
- **Stay on the site.** Navigation to hosts not in `allowed_hosts` is refused, analytics calls are dropped so simulated visits don't distort the site's data, and live runs use at most 2 sessions at a time at the default pace.
- **CAPTCHAs, bot checks and logins belong to a person.** Never attempt or bypass them. A persona who meets one finishes with `blocked_by_site`, and that is a note about the run, not a UX finding.
- **Read the site's terms before a live run.** If they restrict automated access, or are unclear, ask the user to confirm they own the site or have permission, or offer a staging copy instead.

## Workflow

### 1. Set up (once per project)

```bash
python <skill>/scripts/setup_env.py --project .
```

This installs Playwright, Pillow and Chromium under `.ux-visual-crawl/` in the project. Skip it if `.ux-visual-crawl/venv` exists. Run `report.py` with that venv's Python (`.ux-visual-crawl/venv/Scripts/python.exe` on Windows, `.ux-visual-crawl/venv/bin/python` elsewhere), because it needs Pillow. `eyes.py` finds the venv by itself.

### 2. Agree the brief

Collect only what's missing: the start URL, the hosts the flow crosses, what a person is trying to get done there (the task), who the customers are, and whether this is a live site or a test system. If the user has analytics, survey data or a customer profile, build the panel from it rather than from guesses.

| Mode | When | What personas can do |
|---|---|---|
| `observe_only` (default) | Any live site, or whenever the user says not to fill anything | Look, scroll, click, hover, type short search words. Nothing is sent. |
| `test_env` | The user confirms a local or staging system | Also fill and submit forms, with `test:<name>` values from `test_data` or plainly fake words |

### 3. Write the study

Create `ux-crawl-runs/<study-id>/study.json`:

```json
{
  "id": "acme-signup-2026-11",
  "product": "Acme home broadband",
  "mode": "observe_only",
  "start_url": "https://www.acme.com/broadband",
  "allowed_hosts": ["www.acme.com", "join.acme.com"],
  "goal": "Choose a plan and reach the start of the sign-up form",
  "goal_match": "join\\.acme\\.com",
  "max_steps": 30,
  "pace_ms": 1200,
  "stages": [
    {"id": "landing", "label": "Landing page", "match": "/broadband$"},
    {"id": "plans", "label": "Plans", "match": "/plans"},
    {"id": "signup", "label": "Sign-up", "match": "join\\.acme\\.com"}
  ]
}
```

Keep `id` and the folder name short (20 characters or fewer) and each persona `id` to 24 or fewer. Every session writes screenshots several folders deep, and on Windows a path over 260 characters fails; `eyes.py check` warns when the study folder is too deep.

`goal_match` is a pattern on the address bar. A persona that claims `reached_goal` without ever reaching a matching address is recorded as `claimed_goal_unverified`. `stages`, in journey order, give the report its funnel. `test_env` also needs `environment_confirmation` (who confirmed it's a test system) and `test_data` (for example `{"meter": "0000000000"}`). Check the file with `eyes.py check --study <path>`.

Then survey the key pages and write `facts.md` in the study folder: the prices, conditions and promises the site makes, with the page each is on. It goes to the reviewer only, so they can tell when a persona came away with a wrong belief. Personas must know only what they see.

Survey by sight too, through a recon session:

```bash
python <skill>/scripts/eyes.py start --study <study.json> --recon [--device mobile]
```

Then `look`, `zoom`, `scroll` and `click` as a persona would; `act` needs only the `action` here. Recon sessions live in `recon/` and stay out of the analysis. Don't fetch the HTML, run curl, open the page source or use a web-fetch tool for this. The page's markup can say things the screen doesn't (meta descriptions, hidden text, screen-reader labels, comments), and once one of those is in `facts.md` it flows into the review and the report as if a visitor could have seen it. If something can't be read on screen, write that down as a fact about the page instead.

### 4. Create the personas

Read `references/personas.md` and write `personas.json` in the study folder: usually 4 to 8 people who would behave differently, each with a `demographics` block and a `task`. Show the user a one-line summary of each before running, because a panel missing their key customer wastes the whole run.

### 5. Walk each persona

For each persona, start a session, then hand it to its own subagent:

```bash
python <skill>/scripts/eyes.py start --study <study.json> --personas <personas.json> --persona <id>
```

Read `references/walker.md` and give the subagent that brief with the persona JSON, the session path and the driver path filled in, and nothing else. Your knowledge of the site, the findings you expect and the other personas would contaminate the run. Don't steer or rescue a stuck persona: getting stuck is the data.

If you can't run subagents, walk the personas one at a time yourself, working only from that persona's profile and from what the screenshots show.

Every session ends with an exit interview (`eyes.py feedback`). Check that every `sessions/<id>/` has both `journey.json` with an `outcome` and `feedback.json`. If several end as `blocked_by_site`, stop and tell the user rather than burning more runs.

### 6. Compute the flows

```bash
<venv-python> <skill>/scripts/report.py analyze --study-dir <study-dir>
```

This writes `navigation.json` (every persona's path and every step), `flows.json` (per-page bottleneck scores with their parts, plus the funnel), `demographics.json` and the panel's `feedback.json`.

### 7. Review

Give a fresh subagent `references/reviewer.md` with the study folder path. It reads the journeys, the screenshots, `flows.json` and `facts.md`, measures anything it wants to call a contrast problem, and writes `findings.json` and `insights.json`. If you can't run subagents, do this step yourself after all the walks.

### 8. Verify and report

```bash
<venv-python> <skill>/scripts/report.py verify --study-dir <study-dir>
<venv-python> <skill>/scripts/report.py render --study-dir <study-dir>
```

Read the `removed` list in `verified_findings.json`. A finding with a wrong step or box can be corrected against the recording and verified again. Never edit a journey or measurement to make a claim pass.

`report.html` is one self-contained file: the outcomes and paths, the funnel, the bottleneck table, the findings with cropped evidence, the contrast measurements, the panel's demographics, the exit interviews, and the limits.

### 9. Tell the user

Give the headline, then the top three findings by handle with their fix, each persona's outcome in one line, and where `report.html` and the JSON files are. Mention anything that wasn't tested. End with the closing line from `references/tracing.md`.

## Tracing

Readers push back on synthetic findings: "a real user wouldn't do that", "it looks fine on my screen", "so what's our drop-off rate?". Read `references/tracing.md` before answering any follow-up. It defines the handles (`F1` findings, `B1` pages ranked as bottlenecks, `<persona>:M1` measurements, persona ids), the fixed closing line, the trace block (*Persona · Steps · On screen · Measured · Why this severity · What would change it*), and the questions to expect. A trace re-reads the recording and corrects the report if a finding doesn't hold.

## What this can and can't tell you

Good for: things people can't see or misread, buttons that don't look like buttons or don't respond, fine print that changes the offer, prices or promises that contradict each other across pages, requirements that appear late, dead ends, layout that hides the next step on a phone, and differences between kinds of customer.

Not for: conversion rates, true time on task, or screen-reader experience (personas have no accessibility tree, by design). Large-text and keyboard personas are partly role-played, so treat those findings as prompts for a proper accessibility audit.

Files in this skill

  • SKILL.md11.1 KB
  • evals/README.md780 B
  • evals/fixtures/demo-site/KEY.md1.6 KB
  • evals/fixtures/demo-site/server.py10.9 KB
  • evals/observe-only-with-trace/case.yaml420 B
  • evals/observe-only-with-trace/graders/01-three-personas.md114 B
  • evals/observe-only-with-trace/graders/02-nothing-submitted.md184 B
  • evals/observe-only-with-trace/graders/03-names-plan-confusion.md256 B
  • evals/observe-only-with-trace/graders/04-contrast-backed-by-measurement.md189 B
  • evals/observe-only-with-trace/graders/05-refuses-drop-off-rate.md180 B
  • evals/observe-only-with-trace/graders/06-no-hidden-metadata.md198 B
  • evals/observe-only-with-trace/prompt.md490 B
  • evals/staging-signup-crawl/case.yaml598 B
  • evals/staging-signup-crawl/graders/01-four-personas-with-demographics.md223 B
  • evals/staging-signup-crawl/graders/02-navigation-json-per-persona.md147 B
  • evals/staging-signup-crawl/graders/03-feedback-per-persona.md149 B
  • evals/staging-signup-crawl/graders/04-price-contradiction.md210 B
  • evals/staging-signup-crawl/graders/05-exit-fee-contradiction.md149 B
  • evals/staging-signup-crawl/graders/06-measured-contrast.md197 B
  • evals/staging-signup-crawl/graders/07-button-problem.md225 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in data →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.