UX audit playbook
A sourdough starter for the manual review that catches what the AI's preview doesn't. Eight checks. Two minutes each if you know the shape; thirty seconds each once it's habit.
The AI ships pages that work in the happy path. This playbook covers the unhappy paths and the perceptual basics the preview hides.
1. Mobile (360px wide)
Open dev tools, set viewport to 360px wide × 640px tall. Walk through the page.
Look for:
- Horizontal scroll (anything sticking out past the viewport edge)
- Text that overflows containers
- Tap targets smaller than 44×44px
- Two-column layouts that collapsed into "two narrow columns" instead of "one full-width column"
- Stuck-on-top sticky elements that block the page content
This is the single highest-leverage check. Most vibe-coded sites break at 360px because the AI tested at 1440px.
2. Empty state
Find every list / grid / table on the page. Imagine the data is empty. What does the user see?
The two failure modes:
- Blank space — the layout reserves the area but nothing renders. User assumes the page is broken.
- A literal "0 results" — technically correct, emotionally cold. Use the empty case as an onboarding moment ("no scans yet — start by [doing X]").
empty_state_finder catches the JSX shape (.map() without an empty guard) but it can't judge the copy.
3. Loading state
Throttle network to "Slow 3G" in dev tools. Reload. Watch the page render.
Look for:
- Layout shift as content loads (use skeleton loaders or reserved heights)
- Content flashing in unstyled before fonts load (
font-display: swapwith a sensible fallback) - API calls that hang the whole page (every fetch should have a loading state visible within ~100ms)
- Stale data flash (something from the previous page rendering briefly before the new data lands)
4. Error state
Force an error. Disable network, hit a 500, type garbage into a form.
Look for:
- Whitewash crashes (the page goes blank because an error escaped React)
- Generic "Something went wrong" with no context
- Errors that swallow the user's input (form clears on error — they re-type everything)
- Errors that don't say what the user should do next
The fix is always: catch it, explain it, give a next action.
5. Accessibility (the basics)
You don't need to be a WCAG expert. Run these four:
- Tab through the page. Every interactive element should receive focus in a logical order. Focused elements should have a visible ring.
- Read each button + link out loud. "Click here," "Read more," and "Submit" all fail — the screen reader user gets no context.
- Look at every image. Each one needs
alttext (oralt=""if decorative). The AI defaults to no alt. - Check heading hierarchy. Page has one
<h1>. Headings goh1 → h2 → h3without skipping (noh1 → h4).
a11y_audit covers the structural ones; legibility_review covers contrast + sizing. The playbook above catches the perceptual ones the tools can't.
6. Copy (read it aloud)
Read every line of body copy out loud. Where do you trip?
- Stilted sentences ("Furthermore, this furthermore demonstrates…") — AI tells.
- Buzzwords ("supercharge", "leverage", "revolutionary") —
copy_tone_checkflags these. - Excessive em-dashes — also an AI tell.
- Marketing-speak in product UI ("Unlock your potential" on a delete-account button is wrong).
- Inconsistent voice — first page says "you", second page says "users", third says "we" — pick one.
7. Brand surface (the metadata)
Open the page in a private window. Share the URL into a chat (Slack / iMessage / WhatsApp). What does the preview look like?
- Favicon present + correct?
- OG image (and is it the right image, not the placeholder)?
- Title makes sense out of context?
- Description is the actual page summary, not the framework default?
brand_completeness covers 13 checks here. The manual sanity check is faster.
8. Dead links
Click every link. Yes, every one. Including the footer.
Look for:
href="#"placeholders that shipped- Internal routes that 404 (often because the route name drifted)
- Anchor links to IDs that no longer exist
- External links missing
target="_blank"+rel="noopener noreferrer" mailto:/tel:formatted wrong
broken_link_finder automates this. Manual sweep is the fallback for things the tool can't see (e.g. links to private subdomains).
The 30-second version
If you only have 30 seconds:
- Mobile at 360px. Does it work?
- Empty state on the main list. Does it explain itself?
- One screen reader pass on the primary CTA. Does it have meaningful text?
These three catch ~70% of what the eight-check version catches.
How to feed this playbook
Add to it when:
- You catch a UX failure mode that wasn't in the eight checks. Add a ninth.
- A check repeatedly catches nothing because the underlying problem has been solved at a deeper level. Note it (or remove the check if the failure mode is genuinely impossible now).
- A new device / viewport class becomes relevant (e.g. foldables, watches, in-app browsers).
Companion starters
- ux-reference — design tokens + spacing + typography (the build-time companion to this audit-time playbook)
- brand-voice — how to write the copy that passes check #6
- project-starter — the parent shape this slots into
Companion tools (Fizzgig)
| Check | Tool |
|---|---|
| 2. Empty state | fizzgig__empty_state_finder |
| 5. Accessibility | fizzgig__a11y_audit + fizzgig__legibility_review |
| 6. Copy | fizzgig__copy_tone_check + fizzgig__content_quality |
| 7. Brand surface | fizzgig__brand_completeness |
| 8. Dead links | fizzgig__broken_link_finder |
The five tools above collapse into a single fizzgig__audit MCP tool at the June 2026 Audit Suite launch.