Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Audit UX waiting states for web applications with long-running operations (30+ seconds). Use when asked to evaluate, audit, or analyze a product's loading states, wait times, progress indicators, or user experience during slow operations. Requires browser automation (Chrome MCP tools). Generates comprehensive reports with screenshots, checklist evaluation, and prioritized recommendations.
.claude/skills/aiskillstore-ux-waiting-audit/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | 199% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 44% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 36% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 128% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 121% | 0% |
Evaluate how applications handle long-running operations (30+ seconds) using browser automation.
Screenshot First, DOM Second — always take a screenshot when navigating or stuck. Visual inspection beats DOM probing.
📸 Screenshot → 👀 Analyze visually → 🎯 Click coordinates → 📸 Verify → RepeatALWAYS screenshot:
| DOM Approach | Screenshot Approach | |--------------|---------------------| | Complex selectors fail silently | Visual shows exact UI state | | "missing value" gives no info | Image reveals button locations | | 10+ attempts to find element | 1 screenshot → click coordinates | | Can't see actual user experience | See exactly what user sees |
python# 1. Navigate Control Chrome:open_url(TARGET_URL) sleep(2) # 2. ALWAYS screenshot first # Use browser screenshot or html2canvas # Analyze the image before ANY interaction # 3. If interaction needed, prefer coordinates over selectors # After seeing screenshot: "The submit button is at ~(1200, 650)" Control Chrome:execute_javascript("document.elementFromPoint(1200, 650).click()") # 4. Screenshot again to verify
python# 1. Navigate to target URL Control Chrome:open_url(TARGET_URL) sleep(3) # 2. SCREENSHOT - See what loaded # Analyze: What's visible? Where are interactive elements? # 3. Ask user to help identify: # - Which operation to test # - How to trigger it (button location, input needed)
This is often where audits get stuck. Modern SPAs have complex UIs.
python# Strategy 1: Ask user for guidance # "I see the page. Can you describe where the button is or what to click?" # Strategy 2: Use simple, targeted JS Control Chrome:execute_javascript("document.querySelector('button[type=submit]').click()") # Strategy 3: Coordinate-based clicking (after screenshot) Control Chrome:execute_javascript("document.elementFromPoint(X, Y).click()") # Strategy 4: Let user trigger manually # "Please click the button to start the operation, then tell me when it's processing"
Once operation is running:
python# T+0s: Screenshot immediately when operation starts # T+10s: Screenshot after 10 seconds sleep(10) # Screenshot + capture_state.js # T+30s: Screenshot after 30 seconds sleep(20) # Screenshot + capture_state.js # T+Complete: Screenshot when done # Watch for UI changes indicating completion
python# 1. Evaluate screenshots against checklist (see references/checklist.md) # 2. Generate report with annotated screenshots # 3. Prioritize recommendations
❌ WRONG: Keep trying different selectors
→ Wastes time, silent failures
✅ RIGHT: Take screenshot, analyze visually
→ Ask user for help if needed
→ Use coordinate-based clickingThis usually means:
Fix: Use simple one-liner JS, not complex functions.
javascript// ❌ Complex (fails silently) (function() { const elements = []; ... return JSON.stringify(elements); })() // ✅ Simple (clear result) document.body.innerText.substring(0, 500) document.querySelectorAll('button').length document.querySelector('.loading') !== null
Try in order:
document.forms[0].submit()Ask user for:
If user is available: Ask them to trigger the operation manually while you capture screenshots. This avoids navigation complexity.
Always screenshot first. Then run simple state checks:
javascript// Simple one-liners that won't fail silently: // Check for spinner !!document.querySelector('[class*="spin"], [class*="load"], .spinner') // Check for progress bar !!document.querySelector('progress, [role="progressbar"]') // Get visible text (look for status messages) document.body.innerText.substring(0, 1000) // Count results appearing document.querySelectorAll('[class*="result"], [class*="item"]').length
Capture Timeline: | Time | Action | |------|--------| | T+0s | Screenshot + note what triggered | | T+10s | Screenshot + simple state checks | | T+30s | Screenshot + simple state checks | | T+Complete | Screenshot + final state |
Load and evaluate against references/checklist.md. Score each category:
Use template from references/report-template.md.
Look for:
javascript// Partial results appearing document.querySelectorAll('[class*="result"], [class*="item"], li, tr').length // Streaming content document.querySelector('[class*="stream"], [class*="typing"], [class*="cursor"]')
Look for:
javascript// Counters document.body.innerText.match(/\d+\s*(found|processed|complete|%)/gi) // Animations (CSS or JS) document.querySelectorAll('[class*="animate"], [class*="pulse"], [class*="spin"]')
Look for:
javascript// Time remaining text document.body.innerText.match(/(\d+\s*(sec|min|second|minute)|remaining|left|ETA)/gi) // Progress percentage document.querySelector('[role="progressbar"]')?.getAttribute('aria-valuenow')
For each interval, note:
Compare: | Element | T+0s | T+10s | T+30s | Complete | |---------|------|-------|-------|----------| | Results visible | | | | | | Counter/progress | | | | | | Status message | | | | | | Animation active | | | | |
Generate markdown report with:
references/report-template.mdReference these examples of excellent waiting UX:
If possible, test:
javascript// Simulate slow network (if DevTools available) // Or disconnect briefly and observe behavior
| Issue | User Impact | Quick Fix | |-------|-------------|-----------| | Spinner only | Anxiety, abandon | Add status text | | No progress | "Is it stuck?" | Add heartbeat counter | | No cancellation | Trapped feeling | Add cancel button | | Silent completion | Missed results | Add completion animation | | Full-page block | Can't multitask | Move to background |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-20 | pass→pass | 56,774 | 38,574 | -32% | 1 | 1 | 0% | 3,152 | 4,703 | +49% | 0 | 0 | — |
case-01 | fail→fail | 36,855 | 39,541 | +7% | 1 | 1 | 0% | 5,192 | 7,038 | +36% | 0 | 0 | — |
case-02 | fail→fail | 33,566 | 37,812 | +13% | 1 | 1 | 0% | 4,914 | 7,891 | +61% | 0 | 0 | — |
case-03 | fail→fail | 44,003 | 21,289 | -52% | 1 | 1 | 0% | 4,728 | 2,713 | -43% | 0 | 0 | — |
case-04 | fail→fail | 15,084 | 22,647 | +50% | 1 | 1 | 0% | 1,794 | 2,820 | +57% | 0 | 0 | — |
case-05 | fail→pass | 17,891 | 39,638 | +122% | 1 | 1 | 0% | 2,923 | 8,731 | +199% | 0 | 0 | — |
case-06 | pass→pass | 32,963 | 46,728 | +42% | 1 | 1 | 0% | 4,769 | 5,034 | +6% | 0 | 0 | — |
case-07 | fail→pass | 21,590 | 26,427 | +22% | 1 | 1 | 0% | 2,598 | 3,729 | +44% | 0 | 0 | — |
case-08 | pass→pass | 17,991 | 17,174 | -5% | 1 | 1 | 0% | 1,997 | 3,837 | +92% | 0 | 0 | — |
case-09 | fail→pass | 18,960 | 11,610 | -39% | 1 | 1 | 0% | 2,410 | 3,267 | +36% | 0 | 0 | — |
case-10 | fail→fail | 26,161 | 12,007 | -54% | 1 | 1 | 0% | 2,115 | 4,398 | +108% | 0 | 0 | — |
case-15 | fail→pass | 36,636 | 26,302 | -28% | 1 | 1 | 0% | 1,748 | 3,992 | +128% | 0 | 0 | — |
case-11 | fail→pass | 29,504 | 26,465 | -10% | 1 | 1 | 0% | 1,587 | 3,511 | +121% | 0 | 0 | — |
case-12 | fail→pass | 34,112 | 30,535 | -10% | 1 | 1 | 0% | 2,790 | 4,436 | +59% | 0 | 0 | — |
case-13 | fail→pass | 27,760 | 15,377 | -45% | 1 | 1 | 0% | 1,913 | 3,798 | +99% | 0 | 0 | — |
case-14 | fail→pass | 19,773 | 10,906 | -45% | 1 | 1 | 0% | 2,338 | 3,869 | +65% | 0 | 0 | — |
case-16 | pass→pass | 25,675 | 12,589 | -51% | 1 | 1 | 0% | 1,819 | 3,286 | +81% | 0 | 0 | — |
case-17 | pass→pass | 16,428 | 28,841 | +76% | 1 | 1 | 0% | 1,938 | 3,959 | +104% | 0 | 0 | — |
case-18 | fail→pass | 24,923 | 22,239 | -11% | 1 | 1 | 0% | 1,163 | 3,626 | +212% | 0 | 0 | — |
case-19 | fail→pass | 17,324 | 20,254 | +17% | 1 | 1 | 0% | 1,966 | 3,280 | +67% | 0 | 0 | — |
case-21 | fail→pass | 33,904 | 30,587 | -10% | 1 | 1 | 0% | 2,164 | 4,191 | +94% | 0 | 0 | — |
case-22 | pass→pass | 26,529 | 25,555 | -4% | 1 | 1 | 0% | 1,644 | 4,176 | +154% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 20 counted toward the lift figure. The other 2 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +50 percentage points is the difference between those two pass rates over the 20 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.